酷勤网 – 程序员的那点事!

首页 > 编程资料 > C/C++语言 > 正文

如何让程序打印它自己??

浏览次数: 2007年05月04日 作者:sega6666 字号:

:em17: 
我还是个学生,请前辈们多指教。
我们这次作业思考题有一道是让我们编个程序
而最后打印出的结果是这个程序它自己!
请问前辈们我应该怎么些这个程序呢?
前提我现在只学了main函数,数组等基本知识
指针什么的都没学到!
老师让我们用现在所学的知识编出来,我不会!
请前辈们指点,谢谢!



 flw 回复于:2004-10-08 12:06:33

引用:老师让我们用现在所学的知识编出来

不用管老师的话,
只要你编出来就行了。
哪怕是用了指针也无妨。

文件操作学了吗?
如果没有学的话,这个题目是没法做的。

另外,老师指定的操作系统是什么?
编程工具是什么?

DOS + TC ?
WINDOWS + VC?
UNIX + GCC?


 albcamus 回复于:2004-10-08 13:16:13

“程序打印自己”?

倘若是C这种编译型的,那么做“打印”这件事时的“程序”就是可执行文件,已经不是源代码的“自己”了


 不倒翁(A) 回复于:2004-10-08 13:40:06

刚开始学,那你老师的意思很有可能就是用数组保存你的程序了(你赋值字符串给数组,也就是你的程序),要不只有使用文件了


 win_hate 回复于:2004-10-08 14:09:18

It sonuds like a classical problem and it seems to be too hard for a newbie. Anyway, the codes below meet your requist.


char *p = "\xa\x6d\x61\x69\x6e\x28\x29\xa\x7b\xa\x9\x63\x68\x61\x72\x20\x2a\x71\x20\x3d\x20\x70\x3b\xa\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x63\x68\x61\x72\x20\x2a\x70\x20\x3d\x20\x5c\x22\x22\x29\x3b\xa\x9\x77\x68\x69\x6c\x65\x20\x28\x2a\x70\x29\xa\x9\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x5c\x5c\x78\x25\x78\x22\x2c\x20\x2a\x70\x2b\x2b\x29\x3b\xa\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x5c\x22\x3b\x5c\x6e\x25\x73\x22\x2c\x20\x71\x29\x3b\xa\x7d\xa";

main()
{
        char *q = p;
        printf ("char *p = \"");
        while (*p)
                printf ("\\x%x", *p++);
        printf ("\";\n%s", q);
}


./a.out | diff - foo.c


 流川 回复于:2004-10-08 16:50:32

楼上的, 这个程序实在是经典

是不是可以解释一下?


 流川 回复于:2004-10-08 16:59:03

"\xa\x6d\x61\x69\x6e\x28\x29\xa\x7b\xa\x9\x63\x68\x61\x72\x20\x2a\x71\x20\x3d\x20\x70\x3b\xa\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x63\x68\x61\x72\x20\x2a\x70\x20\x3d\x20\x5c\x22\x22\x29\x3b\xa\x9\x77\x68\x69\x6c\x65\x20\x28\x2a\x70\x29\xa\x9\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x5c\x5c\x78\x25\x78\x22\x2c\x20\x2a\x70\x2b\x2b\x29\x3b\xa\x9\x70\x72\x69\x6e\x74\x66\x20\x28\x22\x5c\x22\x3b\x5c\x6e\x25\x73\x22\x2c\x20\x71\x29\x3b\xa\x7d\xa"; 


刚测试了一下,以上的代码就是涵数体的变形用十六进制的形式表现出来!

其实就是打印两遍,一遍打印自身,一遍打印涵数体

不错不错,高,实在是高!


 流川 回复于:2004-10-08 17:01:20

那还可以把它转化而以\000开头的用八进制表示


 流川 回复于:2004-10-08 17:06:27

还有没有更好的方法?

上面的代码好像还要事先把源代码转化成字符串

有没有办法自动生成啊??


 FH 回复于:2004-10-08 17:18:49

俺记得前一阵俺也写过一个,再贴一次吧。
#include <stdio.h>;

int main()
{
   FILE *f;
   char c;

   if ( ( f = fopen( __FILE__, "r" ) ) != NULL ) {
      while ( fread( &c, 1, 1, f ) == 1 )
          frwite( &c, 1, 1, stdout );
      fclose( f );
   }
   return 0;
}

这个实现要求文件操作的知识,而win_hate兄的则不需要;但是这个程序可在任何字符集的机器上得到正常结果,而win_hate兄的只能在ASCII字符集的机器上得到正常结果。当然把win_hate兄的实现稍做改动也是可以达到同样目的的,但那样就没有现在这样的悬念了,呵呵。


 aero 回复于:2004-10-08 17:20:37

呵呵,还可以用__FILE__来实现哦。不过,是偷懒的办法了。


 aero 回复于:2004-10-08 17:21:58

^_^,FH兄发上来了哈。


 converse 回复于:2004-10-08 17:43:02

无语,一个刚学c的学生碰到这样的老师只能自认倒霉了--不引导学生学习一些实用的编程技术,编程思想却来这么一个偏、怪的题目,唉........
这位同学,这个老师的课不上也罢了,找来老谭的书或者K&R的书自己来看吧(这两本书都有习题集),然后自己上机实践吧,不懂的上来问吧,不要给这个老师引到一些偏门去了。


 picobsd 回复于:2004-10-08 18:09:17

我觉得他的要求是打印程序,而不是打印源代码,思路是这样的,通过读取进程表等方法可获得当前进程的路径,open这个文件,然后按16进制打印出来就可以了


 win_hate 回复于:2004-10-08 18:20:19

如何“生成源代码”,按 it 界的标准,算得上是历史悠久的问题了。它是前辈黑客的游戏,请参考这篇文章,Ken Thompson 得图灵奖后发表的演讲:

http://www.acm.org/classics/sep95/

这篇文章与 unix 历史上的  login 后门有关。


 sega6666 回复于:2004-10-08 20:42:51

哦,多谢前辈们!今天我刚下课回来!老师出的这个只是个思考题!
他说的答案是
#include<stdlib.h>;
void main()
{
     system("type a.c")/*这个程序保存成a.c
}

对不起,之前没说清楚我现在学的是C用的是VC++6.0


 aero 回复于:2004-10-08 21:15:56

晕死,你们老师的答案也太……


 sega6666 回复于:2004-10-08 21:29:58

这个答案怎么了????说完整啊,很想知道,谢谢


 win_hate 回复于:2004-10-08 21:39:07

我也晕。

按你们老师的做,他说得没错。


 THEBEST 回复于:2004-10-08 22:35:15

1。 
char*f="main(){putchar('c');putchar('h');putchar('a');putchar('r'); 
putchar('*');& 
putchar('f');putchar('=');putchar(34);printf(f);putchar(34); 
putchar(';');& 
putchar(10);printf(f);putchar(10);}"; 
main(){putchar('c');putchar('h');putchar('a');putchar('r'); 
putchar('*');putchar('f');& 
putchar('=');putchar(34);printf(f);putchar(34);putchar(';'); 
putchar(10);& 
printf(f);putchar(10);} 

2。 
char*f="char*f=;main(){f[7]=0;printf(f);putchar(34);f[7]=';'; 
printf(f);& 
putchar(34);f[8]=0;printf(&f[7]);f[8]='m';putchar(10); 
printf(&f[8]);putchar(10);}"; 
main(){f[7]=0;printf(f);putchar(34);f[7]=';';printf(f);putchar(34);& 
f[8]=0;printf(&f[7]);f[8]='m';putchar(10);printf(&f[8]); 
putchar(10);} 

3。 
char*f="char*f=%c%s%c;%cmain(){printf(f,34,f,34,10,10);}%c"; 
main(){printf(f,34,f,34,10,10);} 

4。 
char a='"';char b='\n';char c='\\'; 
char*f="char a='%c';char b='%cn';char c='%c%c';%cchar*f=%c%s%c;%cmain(){& 
printf(f,a,c,c,c,b,a,f,a,b,b);}%c"; 
main(){printf(f,a,c,c,c,b,a,f,a,b,b);} 

5。 
char*lines[]={ 
"char*lines[]={", 
"%c%s%c%c%c", 
"0};", 
"main(){", 
"int idx;", 
"puts(lines[0]);", 
"for(idx=0;lines[idx]!=0;idx++){", 
"printf(lines[1],34,lines[idx],34,',',10);", 
"}", 
"puts(lines[2]);", 
"for(idx=3;lines[idx]!=0;idx++){", 
"puts(lines[idx]);", 
"}", 
"}", 
0}; 
main(){ 
int idx; 
puts(lines[0]); 
for(idx=0;lines[idx]!=0;idx++){ 
printf(lines[1],34,lines[idx],34,',',10); 


puts(lines[2]); 
for(idx=3;lines[idx]!=0;idx++){ 
puts(lines[idx]); 





 win_hate 回复于:2004-10-08 22:44:08

http://www.cgl.uwaterloo.ca/~csk/washington/sdc_paper/index.html


 sega6666 回复于:2004-10-08 22:48:11

因为我刚开始学不久,C还没有完全学完,刚学习了数组,所以请前辈们不弃多指点指点我,谢谢你们!~晚辈在这里向你们敬礼了!~


 FH 回复于:2004-10-09 08:38:01

楼主的老师真不愧是中国的老师!让我想起了大跃进时用农村的大柴锅炼钢的创意——真土!


 黄山松 回复于:2004-10-09 09:20:21

倒,那干吗还号称要把程序的源代码打印出来啊,直接说打印一个文件内容不就明白啦!


 biwu 回复于:2004-10-09 10:09:00

我倒是觉得这个老师的答案非常好,大家不要让聪明蒙蔽了自己的眼睛


 win_hate 回复于:2004-10-09 10:21:11

引用:原帖由 "biwu"]我倒是觉得这个老师的答案非常好,大家不要让聪明蒙蔽了自己的眼睛
 发表:



引用:原帖由 "黄山松"] 倒,那干吗还号称要把程序的源代码打印出来啊,直接说打印一个文件内容不就明白啦!
 发表:



引用:原帖由 "win_hate" 发表:

如何“生成源代码”,按 it 界的标准,算得上是历史悠久的问题了。它是前辈黑客的游戏




 wqzunix 回复于:2004-10-09 11:12:30

:( [color=red][/color][size=18][/size][size=12][/size]
看到这么多人发表的高见,我真是汗颜,
对于编程这个问题我真的是太不懂了,希望各位才人高手多指点指点!!!!


 sega6666 回复于:2004-10-09 11:43:19

引用:原帖由 "黄山松"]倒,那干吗还号称要把程序的源代码打印出来啊,直接说打印一个文件内容不就明白啦!
 发表:



 :shock: 老师的答案也可以叫做是打印一个文件内容吧!
              不过老师说的也没错吧!
              两种都可以编出这种结果吧!


 win_hate 回复于:2004-10-09 12:05:42

对一个问题的理解与具体的环境有关。同样的一句话,可能在你们的课堂环境中是很清楚的,没有歧义的,但转到这里来之后,就被误解了。

既然楼主的问题已经解决,这个贴子就不必再顶了吧?


 sega6666 回复于:2004-10-09 12:16:00

是,老大!


 czyf2001 回复于:2004-10-11 09:58:10

win_hate的程序是很有技巧!

其实*p以%c打印出来,就是以main开始的主程序!


呵呵,这种思路真的能让人迷惑啊!

牛人就是强!
强!!


 l4kernel 回复于:2007-04-28 00:11:32

这个就是所谓quine,其实很简单,和用什么数进制表达无关。

程序分为三部分:
1,字符串s,内容是s后的全部内容,包括"\n""\t"等;
2,函数定义(如果需要)
3,主函数,打印“s="”+s内容(显示escape sequences)+s内容(不显示escape sequences)

学过可计算理论的可以用不动点定理证明这种程序的存在。并且程序源码不仅是可以被打印,而是可以作为本程序自己的输入,所以也可以写个程序,输出程序自己的长度/MD5等等。

老师出这个题目并没有什么不妥,quine是很有趣的问题。


 cjaizss 回复于:2007-04-28 00:21:12

病毒的思想


 emacsnw 回复于:2007-04-28 05:52:47

也来一个:

char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}




[bohnanza:misc]$ cc test.c -o test
[bohnanza:misc]$ cat test.c
char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}
[bohnanza:misc]$ ./test
char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}



 emacsnw 回复于:2007-04-28 05:57:39

引用:原帖由 emacsnw 于 2007-4-27 13:52 发表
也来一个:

char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}




[bohnanza:misc]$ cc test.c -o test
[bohnanza:misc]$ cat tes ... 



刚看到前面有人回帖已经有这个了,貌似用C写的话这个是最短的了(就我所知)。
不知道有没有大侠能够证明一下,最短的这样的C程序至少要多长。应该比较有趣啊,呵呵。


 yuanchengjun 回复于:2007-04-28 09:04:12

大家不要丢我砖。

嗯,这个问题么,从软件工程的角度看,很简单,
就是需求没有搞明白。就是程序的具体功能没有搞明白。

还是比较喜欢ACM赛题,不仅有说明,而且有例子;
一次笔试,“请描述你打算使用的数据结构用来实现XX的功能。”
结果,我认为么,写个数据结构就OK了。
结果人家要整个算法实现。无语了。


 cugb_cat 回复于:2007-04-28 09:18:34

引用:原帖由 win_hate 于 2004-10-8 14:09 发表
It sonuds like a classical problem and it seems to be too hard for a newbie. Anyway, the codes below meet your requist.


char *p = "\xa\x6d\x61\x69\x6e\x28\x29\xa\x7b\xa\x9\x63\x68\x ... 


对版主的敬仰犹如滔滔江水啊~~~~~~~
实在是佩服佩服
不过还是不太明白原理,版主老大给解释一下好吗?


 zhuomingliang 回复于:2007-05-03 23:20:48

from:http://www.cgl.uwaterloo.ca/~csk/washington/sdc_paper/index.html
都放这里:em12:
感谢21楼win_hate
引用:Appendix A: Source Code
This appendix contains all the individual programs which appear in the report, along with the ones which are referred to but which to not appear in the body of the report. 

Failure I 

    char*f="main(){printf(f);printf(f);}";main(){printf(f);printf(f);}

Failure II 

    char*f="main(){printf("char*f="");printf(f);printf("";\n");printf(f);}";
    main(){printf("char*f="");printf(f);printf("";\n");printf(f);}

Failure III 

    char*f="main(){printf(\"char*f=\"\");printf(f);printf(\"\";\\n\");printf(f);}";
    main(){printf("char*f=\"");printf(f);printf("\";\n");printf(f);}

Self 0 

    char*f="main(){putchar('c');putchar('h');putchar('a');putchar('r');putchar('*');&
        putchar('f');putchar('=');putchar(34);printf(f);putchar(34);putchar(';');&
        putchar(10);printf(f);putchar(10);}";
    main(){putchar('c');putchar('h');putchar('a');putchar('r');putchar('*');putchar('f');&
        putchar('=');putchar(34);printf(f);putchar(34);putchar(';');putchar(10);&
        printf(f);putchar(10);}

Self I 

    char*f="char*f=;main(){f[7]=0;printf(f);putchar(34);f[7]=';';printf(f);&
        putchar(34);f[8]=0;printf(&f[7]);f[8]='m';putchar(10);printf(&f[8]);putchar(10);}";
    main(){f[7]=0;printf(f);putchar(34);f[7]=';';printf(f);putchar(34);&
        f[8]=0;printf(&f[7]);f[8]='m';putchar(10);printf(&f[8]);putchar(10);}

Self II 

    char*f="char*f=%c%s%c;%cmain(){printf(f,34,f,34,10,10);}%c";
    main(){printf(f,34,f,34,10,10);}

Self III 

    char a='"';char b='\n';char c='\\';
    char*f="char a='%c';char b='%cn';char c='%c%c';%cchar*f=%c%s%c;%cmain(){&
        printf(f,a,c,c,c,b,a,f,a,b,b);}%c";
    main(){printf(f,a,c,c,c,b,a,f,a,b,b);}

Self IV 

    char*lines[]={
    "char*lines[]={",
    "%c%s%c%c%c",
    "0};",
    "main(){",
    "int idx;",
    "puts(lines[0]);",
    "for(idx=0;lines[idx]!=0;idx++){",
    "printf(lines[1],34,lines[idx],34,',',10);",
    "}",
    "puts(lines[2]);",
    "for(idx=3;lines[idx]!=0;idx++){",
    "puts(lines[idx]);",
    "}",
    "}",
    0};
    main(){
    int idx;
    puts(lines[0]);
    for(idx=0;lines[idx]!=0;idx++){
    printf(lines[1],34,lines[idx],34,',',10);
    }
    puts(lines[2]);
    for(idx=3;lines[idx]!=0;idx++){
    puts(lines[idx]);
    }
    }

(Self IV assumes in advance that it will be iterating across an array of strings rather than a single string. It iterates across the array the first time to output the mention, namely the definition of the array. The second iteration provides outputs the use). 
Cheat I 

    extern void print_a_prog();
    main(){print_a_prog();}

Cheat II 

    #include 
    main(){
        int c;
        FILE *f;
        f = fopen( __FILE__, "r" );
        c = fgetc( f );
        while( c != EOF ) {
            putchar( c );
            c = fgetc( f );
        }
        fclose( f );
    }

Cheat III 

    main(){
        Find myself in the computer's memory.
        Output all the bits that make me up.
    }



[ 本帖最后由 zhuomingliang 于 2007-5-3 23:23 编辑 ]


 xiaomiao 回复于:2007-05-04 10:33:35

fopen( __FILE__, "r" ) 调用中__FILE__是什么文件的指针?


 win_hate 回复于:2007-05-04 10:44:42

占个位置, 第 3000 帖了。

40 楼,好高啊........

[ 本帖最后由 win_hate 于 2007-5-4 10:47 编辑 ]







 emacsnw 回复于:2007-05-04 11:22:28

引用:原帖由 win_hate 于 2007-5-3 18:44 发表
占个位置, 第 3000 帖了。

40 楼,好高啊........ 



数字不错,还有777。