前几天老师在帮我调程序的时候说我滥用格式字符,主要是当时学C语言只记住了%c、%d这类常用的格式字符,其它的都没记住,所以就跟着感觉乱用了。下面给出滥用的例子各位引以为戒。
输出指针应该用格式字符%p,而我在程序里用了%d,尽管程序运行时没有出错,但是很不提倡大家这样乱用,因为有时候将会导致难以预料的错误。下面给出《C陷阱与缺陷》一书中提到的一个滥用格式字符导致错误的例子。
书中说这个程序在某个编译器的输出是0 0 0 0 0 1 2 3 4
为什么会这样呢,为什么会这样呢,问题的关键在于,这里c被声明为char类型,而不是int类型。当程序要求scanf读入一个整数,应该传递给它一个指向整数的指针。而程序中scanf函数得到的却是一个指向字符的指针,scanf函数并不能分辨这种情况,它只是将这个指向字符的指针作为指向整数的指针而接受,并且在指针指向的位置存储一个整数。因为整数所占的存储空间要大于字符所占的存储空间,所以字符附近的内存将被覆盖。
根据上面的解释我在gdb下对程序进行了调试,编译出二进制文件为test,调试结果如下。
仔细分析上面调试的效果。第一次在第13行输入305,这时查看c的内存为0xbfc83193,i的内存为0xbfc83194。305的四字节十六进制数为0×0000,0000,0001,0031,赋值的结果是0×0031被赋给内存0xbfc83193,0×0001被赋给内存0xbfc83194,0×0000被赋给内存0xbfc83195,0×0000被赋给内存0xbfc83196。这时c的值为字符‘1’,i的值为整数1,所以循环继续。第二次输入1073,i编程4,for循环结束,程序结束。
另外上面的程序在进行调试时如果在等待接收整数而接收到的是字母时,也即在等待输入时输入字母,程序的输出是0 1 2 3 4,具体原因没有深究。希望感兴趣的朋友试一试。
回过头来看开头提到的我写的错误代码。因为在32位机上指针和整数一般都是4字节的,而所有的东西在机器里都是以2进制存储,所以输出是只是相当于把16进制转换成10进制进行了输出。并没有错误出现。
不管怎么样,在进行格式化输入输出的时候,大家尽量还是要正确使用格式字符,以免造成不必要的麻烦。我在另一篇文章中将给出详细格式字符的说明。