一段有趣的C程序

原创 2004年09月22日 12:19:00

一段有趣的C程序

最近在一个论坛发现了一段简单的C程序很有意思,其中蕴含着不少技巧,在此与大家分享一下。

原程序如下:

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

#include <stdio.h>

main(_){char*x="*b#**000**I#*******2*0***#-.****5.*-#-.****54.#*******2**6#****00**0.#";while(_=*x/4)_-=8,printf("/n%*s"+!!_,_+_,"_/_/_/"+*x++%4*2);}

 

表面看起来很奇怪的代码,我把它放到VC++6下面编译,发现不能通过,提示”_”未声明,对以上代码稍加修改,如下:

 

#include <stdio.h>

main(int _){char*x="*b#**000**I#*******2*0***#-.****5.*-#-.****54.#*******2**6#****00**0.#";while(_=*x/4)_-=8,printf("/n%*s"+!!_,_+_,"_/_/_/"+*x++%4*2);}

 

细心的人已经看出来了,就是在main函数的参数”_”前面加上了变量的类型:int。此时,以上代码在VC6中就能够正常的编译和连接了。运行的结果如下:

  _/                              _/

  _/  _/  _/_/_/  _/_/_/  _/_/_/  _/  _/                _/_/

  _/  _/  _/  _/  _/  _/  _/      _/  _/  _/_/_/  _/  _/  _/

  _/_/    _/  _/  _/  _/  _/      _/_/    _/  _/  _/_/

  _/_/    _/  _/  _/  _/  _/      _/_/    _/_/_/    _/

  _/  _/  _/  _/  _/  _/  _/      _/  _/  _/        _/

  _/  _/  _/  _/  _/_/_/  _/_/_/  _/  _/  _/_/_/    _/

是用”_/”组成的单词“knocker”。

下面我们来分析这个小小的程序,不过为了看起来直观,我把这个程序稍加改动:

 

#include <stdio.h>

main(int _){

       char*x="*b#**000**I#*******2*0***#-.****5.*-#-.****54.#*******2**6#****00**0.#";

       while(_=*x/4)

       {

              _-=8;

              printf("/n%*s"+!!_,_+_,"_/_/_/"+*x++%4*2);

       }                                           

}

 

首先来看看main函数参数,这个参数的名称比较奇怪”_”,我们看着有些不习惯,但它确实是合法的变量名称。另外,本来我们常见的main函数一般都不带参数,如果有参数是因为程序希望处理命令行格式下运行这个程序所需要的参数,一般是这样的:main(int argc, char **argv),第一个参数argc表示参数表中参数的个数,argc是一个char型二维数组,保存着参数字符串。举个例子,如果我们在命令行下输入命令:dir –s c:/

此时,argc的值为3(包括命令本身),argv[0]指向字符串:dirarg[1] 指向字符串:-sarg[2]指向字符串c:/。那么既然main函数的参数通常要不没有,要不就是两个,而这个程序只有一个,这样做是否合法呢?答案是肯定的!我在《关于C语言中的变量》中提到过,函数中的参数是保存在堆栈中的,所以这就涉及到一个谁来平衡堆栈的问题,是调用者还是被调用者。在使用VC6编译器的时候,如果函数没有特别的声明,默认是调用者清理堆栈。换句话说,运行时库(runtime)调用main函数的时候,只传递一个参数给main函数,这一点它自己是知道的,当main函数调用结束以后,它在平衡堆栈的时候,只清除掉一个函数,因此不会出现任何问题。

 

我们接着往下看,下面定义了一个char型指针变量x,指向一个字符串。接下来是while语句,while(_=(*x)/4),但表达式_=(*x)/4的值不为0的时候就执行while的循环体,然而表达式_=(*x)/4是一个赋值语句,它的值又是多少呢?在这种情况下,通常赋值号右面的表达式的值就是整个表达式的值。第一次执行这个语句的时候,x指向字符’*’,对应的值为42,以此类推,当x=0时,也就是字符串结束的时候,循环结束。

 

接下来在原来的程序中是:_-=8,printf("/n%*s"+!!_,_+_,"_/_/_/"+*x++%4*2);这里的逗号作用有些类似分号,但是逗号两侧组成的是一条语句,而分号则是两条语句。

我们仔细看printf这条语句,它的格式字符串为:”/n%*s”,其中%*s很少见,很多人不知道这是什么格式,不过我们可以在MSDN中找到这样的描述:

If the width specification is an asterisk (*), an int argument from the argument list supplies the value. The width argument must precede the value being formatted in the argument list.

意思是说如果宽度用星号(*)来指定,则应该在参数列表中提供一个int型参数作为宽度的值。这样就清楚了,原来这个printf语句是用表达式_+_来控制字符串”%*s”的宽度,也就是替换其中的(*)。

在仔细一看,原来格式字符串还没有完!完整的应该是:"/n%*s"+!!_。这就奇怪了,字符串怎么和!!_相加呢?其实也不奇怪,在这里!!_是对变量_作了两次“非”的操作,结果应该是01。要明确的是,字符串作为参数传递给函数的时候,只是把字符串的首地址传递给了函数,所以字符串"/n%*s"的首地址就是字符’/n’的地址,当这个地址加1的时候,传递给printf函数的格式字符串就变成了"%*s",所以这个+!!_的奥妙就在于控制换行!是不是很有创意?

当然了,下面的代码同样有创意,就是printf语句要打印的字符串参数:"_/_/_/"+*x++%4*2。经过刚才的分析,我们不难理解"_/_/_/"加上后面的表达式的用意了,同样是控制输出字符的个数,是一个”_/”,两个,还是三个。那么关键就是后面这个表达式了:*x++%4*2。其实慢慢的分析也不困难,先执行*x%4*2,然后执行x++。所以,当在执行while语句的时候,x会指向下一个字符!

 

综上所述,这个小程序就是利用一个字符串来控制输出的例子,里面运用了很多技巧,对于初学者需要很好的理解,对今后的编程是很有帮助的!

 

一个有趣的C语言程序,谁说程序员不懂浪漫

浏览看雪论坛,发现有人讲了一个有趣的C语言程序。原帖地址:http://bbs.pediy.com/showthread.php?p=389887我做了一点点的修改,最后打印出 i O y(中间那个是...
  • xueerfei008
  • xueerfei008
  • 2013年07月08日 16:01
  • 52638

C语言比较有意思的几个小程序

#includeconio.h>main()...{    int i;    char *s[]=...{"BLACK","BLUE","GREEN","CYAN",    "RED","MAGEN...
  • wangjiaoni
  • wangjiaoni
  • 2007年07月08日 23:31
  • 20013

一段有趣的代码

把以下代码复制到IE地址栏里按回车,嘿嘿javascript:R=0; x1=.1; y1=.05; x2=.25; y2=.24; x3=1.6; y3=.24; x4=300; y4=200; x...
  • xbin8
  • xbin8
  • 2008年03月08日 21:48
  • 601

两个好玩的C语言程序

1.写一个c语言程序,输出hello,删掉代码的第一个字符,输出world。 2.写一个c语言程序,输出hello,删掉代码的最后一个字符,输出world。 想了一会,写出了这两个代码,哈哈,再次膜...
  • t1019256391
  • t1019256391
  • 2013年08月28日 20:29
  • 2461

一段有趣的程序

 result love(boy, girl)     {     if( boy.有房() and boy.有车() )     {                         boy.set(...
  • coder2010
  • coder2010
  • 2008年11月24日 10:04
  • 396

一段有趣的C++代码,五次选择猜出你的生日

程序代码:GuessBirthDate.cpp /** * 运行程序,做5次选择,就能知道你的生日是哪一天。 */ #include using namespace std; int ma...
  • qq_30062589
  • qq_30062589
  • 2017年02月01日 22:25
  • 1727

有趣的C语言问题 测试你对C语言的熟悉程度

下面这个程序输出什么?enum {false,true};int main(){        int i=1;        do        {                printf...
  • matrix67
  • matrix67
  • 2008年02月03日 21:35
  • 395

C/C++趣味程序百例

1.绘制余弦曲线  2.绘制余弦曲线和直线  3.绘制圆  4.歌星大奖赛  5.求最大数  6.高次方数的尾数  7.阶乘尾数零的个数    8.借书方案知多少  9.杨辉三角形  ...
  • Crystal_lpx
  • Crystal_lpx
  • 2014年08月17日 22:24
  • 1636

一段有趣的C++程序

  阅读下面的程序,看看输出是什么? #include using namespace std; class A { public:    ...
  • Nocky
  • Nocky
  • 2008年10月27日 11:54
  • 1137

简单,但是非常有趣的两段c代码!

/* Note:Your choice is C IDE */ #include "stdio.h" #include "windows.h" #include "malloc.h" ...
  • u012187684
  • u012187684
  • 2014年04月28日 12:53
  • 471
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一段有趣的C程序
举报原因:
原因补充:

(最多只允许输入30个字)