Trang 1 trên tổng số 3 123 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 29 kết quả

Đề tài: Chương trình in source của chính nó trong lập trình C

  1. #1
    Ngày gia nhập
    09 2006
    Nơi ở
    /usr/share/.hack@
    Bài viết
    1,433

    Talking Chương trình in source của chính nó trong lập trình C

    Sau hồi lâu cũng được một ví dụ

    C Code:
    1. #include <stdio.h>
    2. char *program = "#include <stdio.h>%cchar *program = %c%s%c;%cint main()%c{%c
    3. printf(program, 10, 34, program, 34, 10, 10, 10, 10, 10, 10);%c    return 0;%c}%c";
    4. int main()
    5. {
    6.         printf(program, 10, 34, program, 34, 10, 10, 10, 10, 10, 10);
    7.         return 0;
    8. }

    Một bài in source của chính nó đây .
    Bác nào có bài nào hay vác vào đây để sưu tập phát
    None!

  2. #2
    Ngày gia nhập
    06 2007
    Nơi ở
    C:\WINDOWS\system32\dllcache\
    Bài viết
    3,006

    Chương trình tự tái sinh

    Một trong các bài tập rất hay cho người đang học lập trình (bất kể ngôn ngữ nào) là: hãy viết một chương trình in chính nó ra. Chú ý là phải in ra giống hệt, từng giòng từng chữ từng cái xuống hàng. Ở đây ta giả sử có thể viết chương trình bằng một tệp (file) thôi.

    Nếu bạn chưa bao giờ nghĩ về các chương trình kiểu này, hãy dành vài chục phút nghĩ trước khi đọc các ví dụ dưới đây. Bạn sẽ thấy bài tập này liên quan mật thiết đến khái niệm "tự tham chiếu", một trong những khái niệm trung tâm trong bài Chung qui chỉ tại Cantor.

    Thử xét vài ví dụ sau:

    * C/C++:
    C Code:
    1. main(){char *c="main(){char *c=%c%s%c;printf(c,34,c,34);}";printf(c,34,c,34);}

    * Java:

    Code:
    import java.text.*;class a{public static void main(String x[]){char b[]={34};
    
    char c[]={123};String s[]=new String[3];s[0]="import java.text.*;class a{2}
    
    public static void main(String x[]){2}char b[]={2}34};char c[]={2}123};
    
    String s[]=new String[3];s[0]={1}{0}{1};s[1]=new String(b);s[2]=new String(c);
    
    System.out.println(MessageFormat.format(s[0],s));}}";s[1]=new String(b);s[2]=
    
    new String(c);System.out.println(MessageFormat.format(s[0],s));}}
    * Common Lisp:

    Code:
    ((lambda (x)
    
    (list x (list (quote quote) x)))
    
    (quote
    
    (lambda (x)
    
    (list x (list (quote quote) x)))))
    
        * Perl:
    
    #!/usr/bin/perl
    
    $_=<<'eof';eval $_; print "#!/usr/bin/perl\n\$_=<<'eof';eval \$_;\n${_}eof\n" 
    
    eof

    Các ví dụ trên tôi lấy ở đây, và ở đây. Dưới đây ta sẽ thiết kế một ví dụ cho riêng ta, không cần đi "chôm" về. Các trương trình tự in bản thân còn được gọi là Quine, họ của triết gia Willard van Orman Quine. Có hai câu hỏi liên quan:

    1. Có nguyên tắc gì để viết các chương trình lọai này không? Cho một ngôn ngữ mới thì làm thế nào ta viết được một chương trình như vậy?
    2. Các chương trình lọai này có ứng dụng gì không?

    Trước hết, ta bàn về nguyên tắc viết các chương trình tự in được bản thân. Ta sẽ làm việc trên một mô hình tổng quát (nhưng hoàn có thể hiện thực được với bất kỳ ngôn ngữ máy tính nào). Giả sử trong mô hình máy tính này có một vùng nhớ mà tất cả các chương trình đều lấy input từ đó và ghi ra đó được. Có hai quan sát nhỏ:

    1. Cho một chuỗi x bất kỳ, ví dụ x = "học như nghịch thủy hành châu", gọi P(x) là chương trình ghi x vào vùng nhớ chung. Có thể có nhiều P(x) khác nhau, ta cứ thống nhất một loại P(x) duy nhất. Bạn có thể nghĩ đến phát biểu

    strcpy(buffer, "Học như nghịch thủy hành châu");

    trong ngôn ngữ C chẳng hạn.

    2. Cho một chuỗi x bất kỳ trong vùng nhớ, ta có thể dễ dàng viết một đoạn chương trình sẽ ghi P(x) vào vùng nhớ.

    Ý tưởng của chương trình tự in bản thân (vào vùng nhớ chung) như sau: chương trình này có hai đoạn, đoạn A và đoạn B, nghĩa là nối A với B thì ta có toàn bộ chương trình.

    Đoạn B làm công việc như sau:

    1. x = chuỗi các bytes trong vùng nhớ
    2. Ghi P(x) vào vùng nhớ
    3. Ghi x vào vùng nhớ

    Chú ý rằng, sau khi B hoạt động xong thì trong vùng nhớ chung chứa P(x) rồi đến x. Bạn nên tưởng tưởng viết một đoạn chương trình như B trong ngôn ngữ bạn thích.

    Đoạn chương trình A thì làm gì? Nó sẽ ghi x vào vùng nhớ cho B đọc và ghi P(x), x. Thế A ghi gì? A ghi ra chính đoạn B ở trên!!!

    Vì A ghi B vào vùng nhớ, A = P(B), và x = B. Còn B ghi ra "P(x)x" = "P(B)B" = "AB", chính là chương trình ta đang viết.



    Ta thử dùng nguyên tắc mô tả trong ví dụ trước để viết một chương trình C tự in bản thân. Lần thử đầu tiên, chương trình A ghi x vào biến buffer, chương trình B in ra đoạn chương trình P(x), sau đó in x. Kết quả đại khái như sau:

    C Code:
    1. int main() {
    2.  char* buffer = "printf(\"int main() {\\n char* buffer = %s;\\n %s\\n}\\n\", buffer, buffer);";
    3.  printf("int main() {\n char* buffer = \"%s\";\n %s\n}", buffer, buffer);
    4. }

    Lần thử này không thành công lắm, dù chương trình này in ra một chương trình gần giống nó. Vấn đề nằm ở cả đống ký tự thoát (escape characters '\'). Nó in thế này:

    C Code:
    1. int main() {
    2.  char* buffer = "printf("int main() {\n char* buffer = %s;\n %s\n}\n", buffer, buffer);";
    3.  printf("int main() {\n char* buffer = %s;\n %s\n}\n", buffer, buffer);
    4. }

    Rút kinh nghiệm, tôi tránh các escape characters và thay chúng bằng mã ASCII. Mã ASCII của ký tự xuống dòng (linefeed) là 10, và của ký tự ngoặc kép (") là 34. Kết quả lần thử thứ hai cho đoạn chương trình:

    C Code:
    1. int main() {
    2.  char* buffer = "printf(\"int main() {%c char* buffer = %c%s%c;%c %s%c}\", 10, 10, 34, buffer, 34, 10, buffer, 10);";
    3.  printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 34, buffer, 34, 10, buffer, 10);
    4. }

    Chương trình này in ra

    C Code:
    1. int main() {
    2.  char* buffer = "printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 10, 34, buffer, 34, 10, buffer, 10);";
    3.  printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 10, 34, buffer, 34, 10, buffer, 10);
    4. }

    Giống lắm rồi. Nhưng vẫn bị một escape character \ cho dấu " của printf. Lý do là vì cả printf lẫn định nghĩa buffer đều dùng ", mà nếu bỏ " vào trong định nghĩa buffer thì phải escape nó. Nhưng ta hoàn toàn có thể printf mà không dùng " như sau:

    C Code:
    1. int main() {
    2.  char* buf1 = "char buf2[] = {'i', 'n', 't', ' ', 'm', 'a', 'i', 'n', '(', ')', ' ', '{', '%', 'c', ' ', 'c', 'h', 'a', 'r', '*', ' ', 'b', 'u', 'f', '1', ' ', '=', ' ', '%', 'c', '%', 's', '%', 'c', ';', '%', 'c', ' ', '%', 's', '%', 'c', '}', (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);";
    3.  char buf2[] = {'i', 'n', 't', ' ', 'm', 'a', 'i', 'n', '(', ')', ' ', '{', '%', 'c', ' ', 'c', 'h', 'a', 'r', '*', ' ', 'b', 'u', 'f', '1', ' ', '=', ' ', '%', 'c', '%', 's', '%', 'c', ';', '%', 'c', ' ', '%', 's', '%', 'c', '}', (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);
    4. }

    Bạn có thể dịch và chạy thử đoạn trên, in ra chương trình y hệt.



    Chương trình tự tái sinh có nhiều ứng dụng thú vị. "In bản thân" chỉ là một ví dụ của sự tái sinh.

    Các virus máy tính đều có chức năng tái sinh "y chang" này, nhưng thay vì in ra stdout, chúng tự copy bản thân qua một địa chỉ mới (trong bộ nhớ, qua mạng, hay xuống đĩa cứng). Trong bài tiến hóa số tôi có đề cập đến các chương trình máy tính tự tái sinh dùng để mô phỏng tiến hóa của các loại "vi khuẩn số" đơn giản.

    Trong tương lai, bạn có thể tưởng tượng các chương trình phức tạp hơn, hay các robots tự tái sinh. Hy vọng đến đây bạn đã được thuyết phục rằng sự tự tái sinh không phải là thứ vô vọng về mặt triết học.

    Trong các ví dụ trước, ta chỉ thiết kế các chương trình có chức năng duy nhất là in ra bản thân. Còn bọn "vi khuẩn số" hay viruses còn làm các việc khác nữa. Chuyện này không có gì khó. Giả sử ta có chương trình T làm việc gì đó (phá đĩa cứng chẳng hạn), ta có thể thiết kế chương trình ABT bao gồm đoạn A = P(x), đoạn B giống như trước, và đoạn T. Thay vì A ghi x = B vào vùng nhớ, thì trong trường hợp này A sẽ ghi x = BT, còn B thì in P(x)x như cũ. Như vậy ta đã bổ túc cho chương trình T chức năng tự tái sinh mà không cần suy nghĩ gì nhiều.

    Cái mô hình máy có bộ vi xử lý truy cập một vùng nhớ chung của ta chính là mô hình máy Turing. Lần tới ta sẽ dùng ý tưởng về sự tự tái sinh này để chứng minh rằng có bài toán không quyết định được bằng máy Turing (xem thêm chung qui chỉ tại Cantor). Như đã nói trong bài "chung qui chỉ tại Cantor", khái niệm tự tham chiếu là một khái niệm then chốt. Vì thế, cũng không ngạc nhiên lắm khi sự tự tái sinh có liên quan đến vấn đề không quyết định được.

    Bài tập 1: viết một chương trình C chép file X sang file Y, sau đó tự in bản thân nó (C) ra stdout.

    Để minh họa khái niệm tự in và tự tham chiếu một lần nữa, hãy xét ví dụ sau (tôi lấy ở đây):

    * This sentence has three a's, two c's, two d's, twenty-eight e's, four f's, four g's, ten h's, eight i's, two l's, eleven n's, six o's, seven r's, twenty-seven s's, eighteen t's, three u's, five v's, six w's, three x's, and three y's.

    Bài tập 2: viết một chương trình C tìm một câu tiếng Việt có nội dung tương tự.

    Bài tập 3: có phải tất cả các ngôn ngữ đều có một câu dạng này hay không? Ngôn ngữ với tính chất gì thì có một câu như vậy?



    Ta đã "chứng minh" rằng mọi chương trình có thể lấy được đoạn mã của chính nó. (Chứng minh điều này một cách chặt chẽ bằng toán học cũng không có gì khó khăn, tương tự như các ý tưởng ta đã trình bày, chỉ cần định nghĩa rõ ràng thế nào là một chương trình.) Phát biểu này thường được gọi là định lý đệ qui (recursion theorem).

    Đến đây, ta minh họa một ứng dụng của định lý đệ qui. Ta sẽ dùng định lý này để chứng minh rằng bài toán dừng không quyết định được. Tôi sẽ thảo luận ý tưởng chính, bỏ qua các chi tiết toán không quan trọng. Bài toán dừng đại khái có thể phát biểu như sau: "cho một đoạn mã chương trình [M] và một chuỗi w, quyết định xem với input w thì M có dừng sau một số hữu hạn các bước hay không?" (Ta dùng [M] để chỉ đoạn mã của chương trình M.)

    Định lý: không tồn tại chương trình nào giải bài toán dừng.

    Chứng minh: giả sử có chương trình A giải bài toán dừng, ta thiết kế một chương trình M để làm phản chứng như sau

    1. Gọi input của M là w
    2. M tự lấy đoạn mã [M] của chính nó
    3. M chạy A với input là ([M], w).
    4. Nếu A trả lời là "dừng" thì M nhảy vào một vòng lặp vô tận.
    5. Nếu A trả lời là "không dừng" thì M dừng.

    Như vậy A không thể nào quyết định xem M có dừng hay không!

    Chứng minh trên rất đặc trưng cho lập luận đường chéo của Cantor, thường được dùng cho các bài toán mà đối tượng có tính tự tham chiếu. Lý luận kiểu như trên là một trong những công cụ rất mạnh để chứng minh phản chứng trong lý thuyết tính toán.

    Không biết các bạn thế nào chứ lúc đầu tôi thấy việc thiết kế chương trình tự in khá là phản trực quan. (Tưởng tượng một nhà máy sản xuất gỗ lại có thể sản xuất một nhà máy sản xuất gỗ y hệt như nó.) Thế mà câu trả lời không những là có các chương trình như vậy, mà còn có cả một nguyên tắc viết các chương trình đó.

    Trong bài này, ta đã đi từ một câu hỏi tự tham chiếu này (chương trình tự in) sang câu hỏi tự tham chiếu khác (bài toán dừng). Ta dùng câu trả lời có cho câu hỏi đầu để trả lời không cho câu hỏi thứ hai.

  3. #3
    Ngày gia nhập
    09 2006
    Nơi ở
    /usr/share/.hack@
    Bài viết
    1,433

    cái dòng thứ 2 nó có string termination thì phải nối nó lại với cái dòng bên dưới <cuối dòng thứ 2 ấn DEL 1 phát để xóa terminator đi>

    Đã được chỉnh sửa lần cuối bởi langman : 05-03-2010 lúc 05:47 PM.
    None!

  4. #4
    Ngày gia nhập
    04 2010
    Nơi ở
    Recycle Bin
    Bài viết
    358

    đọc cái này dễ 'tẩu' quá!
    nhưng mà cũng chỉ in ra source dạng
    hàm main + chuỗi + printf rất chuối.
    =>hàn lâm và không có áp dụng thực tế.
    YH : lobuocphuudu_218
    Phone : 0126 463 5095

    http://forums.congdongcviet.com/signaturepics/sigpic55872_2.gif

  5. #5
    Ngày gia nhập
    11 2010
    Nơi ở
    Black Hole
    Bài viết
    824

    đây là code của mình :
    C Code:
    1. #include<stdio.h>
    2.  
    3. int main(int argc,char *argv[])
    4. {
    5.   FILE *f=fopen("exo8.c","r");
    6.   char buffer[255];
    7.   while(fgets(buffer,255,f))
    8.     {
    9.       printf("%s",buffer);
    10.     }
    11.   return 0;
    12. }

    Ko biết có lạc đề ko vì code trên quả thật là in ra chính code của nó.
    Nếu sai, xin giải thích rõ câu hỏi, mình hiểu như mình viết code thôi. (file.c của mình ở đây mang tên exo8.c )

  6. #6
    Ngày gia nhập
    03 2009
    Nơi ở
    %appdata%\Temp
    Bài viết
    819

    Mặc định Chương trình in source của chính nó trong lập trình C

    Trích dẫn Nguyên bản được gửi bởi clamvn Xem bài viết
    đây là code của mình :
    C Code:
    1. #include<stdio.h>
    2.  
    3. int main(int argc,char *argv[])
    4. {
    5.   FILE *f=fopen("exo8.c","r");
    6.   char buffer[255];
    7.   while(fgets(buffer,255,f))
    8.     {
    9.       printf("%s",buffer);
    10.     }
    11.   return 0;
    12. }

    Ko biết có lạc đề ko vì code trên quả thật là in ra chính code của nó.
    Nếu sai, xin giải thích rõ câu hỏi, mình hiểu như mình viết code thôi. (file.c của mình ở đây mang tên exo8.c )
    Chương trình in ra chính source của nó ở đây là chương trình in ra chính cái code mà tạo nên nó ý, dù có đặt nó ở bất cứ đâu (không cần file mã nguồn đi kèm)
    Còn như bạn làm thì ko nói làm gì
    .::[The best way to predict the future is to invent it]::.
    __________________________________________________ _ - Alan Kay -

  7. #7
    Ngày gia nhập
    08 2010
    Nơi ở
    Moscow, Russia Federation
    Bài viết
    913

    Thử viết một đoạn bằng C
    C Code:
    1. #include <cstdio>
    2.  
    3. int main() {
    4.     FILE* fp;
    5.     char ch;
    6.     fp = fopen(__FILE__,"r");
    7.     while(1) {
    8.         if (!fread(&ch,sizeof(char),1,fp))
    9.             break;
    10.         fwrite(&ch,sizeof(char),1,stdout);
    11.     }
    12.     fclose(fp);
    13.     return 0;
    14. }
    Mời các bạn ghé thăm blog cá nhân của tôi

  8. #8
    Ngày gia nhập
    11 2010
    Nơi ở
    Black Hole
    Bài viết
    824

    Trích dẫn Nguyên bản được gửi bởi Wazi Armstrong Xem bài viết
    Chương trình in ra chính source của nó ở đây là chương trình in ra chính cái code mà tạo nên nó ý, dù có đặt nó ở bất cứ đâu (không cần file mã nguồn đi kèm)
    Còn như bạn làm thì ko nói làm gì
    Nghía là ko cần mở chính file ngồn mà vẫn in ra dc source à.
    giờ thì hiểu câu hỏi. để nghĩ thử xem

  9. #9
    Ngày gia nhập
    01 2011
    Nơi ở
    -Mountain-
    Bài viết
    768

    Trích dẫn Nguyên bản được gửi bởi Wazi Armstrong Xem bài viết
    Chương trình in ra chính source của nó ở đây là chương trình in ra chính cái code mà tạo nên nó ý, dù có đặt nó ở bất cứ đâu (không cần file mã nguồn đi kèm)
    Còn như bạn làm thì ko nói làm gì
    mình làm bt thì viết chương trình giống giống với anh cà rem....
    còn hum làm theo cách của anh langman thấy nếu dùng suystem("pause"); hay return 0;
    hình như ko đc in ra
    mặt khác thấy mọi người nói làm theo cách của mình chỉ là đọc file thông thường
    còn cách.......... mới là tái sinh.... hic....
    Hướng dẫn C++: https://www.youtube.com/watch?v=BwLodoQdoY4&list=PL1c9Uxlo-mplJDRGdONNupgo5OCBTyGGn

  10. #10
    Ngày gia nhập
    11 2010
    Nơi ở
    Black Hole
    Bài viết
    824

    cách của mp121209 cũng ok.


    A! Đọc bài của langman thì mới hiểu mục đích của bài này.
    Dạng như replicate file source hay có thể nói là nhân bản chương trình lên.
    Nếu thế thì cách của bạn mp121209 ok rồi.
    Đã được chỉnh sửa lần cuối bởi clamvn : 19-04-2011 lúc 07:07 AM.

Các đề tài tương tự

  1. Xử lý đa ngôn ngữ trong MVC [Hướng dẫn + source code]
    Gửi bởi ducnv_b01048 trong diễn đàn Tutorials và Thủ thuật lập trình C#, ASP.NET
    Trả lời: 0
    Bài viết cuối: 13-03-2013, 12:10 PM
  2. Lấy source của trang web trong lập trình C#
    Gửi bởi nhc1987 trong diễn đàn Tutorials và Thủ thuật lập trình C#, ASP.NET
    Trả lời: 5
    Bài viết cuối: 20-08-2011, 11:10 PM
  3. Lỗi không thấy phần Source trong Website ASP.NET trong VB 2k8
    Gửi bởi chuot25 trong diễn đàn Thắc mắc lập trình ASP.NET
    Trả lời: 3
    Bài viết cuối: 15-04-2011, 08:52 PM
  4. Source SQL trong VC++ INSERT INTO
    Gửi bởi MartSoft trong diễn đàn Thắc mắc lập trình Visual C++
    Trả lời: 4
    Bài viết cuối: 16-10-2009, 11:15 PM
  5. Comment trong source - Anh hay Việt ?
    Gửi bởi vpdp_pc trong diễn đàn Kinh nghiệm CNTT
    Trả lời: 5
    Bài viết cuối: 16-09-2008, 07:05 AM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn