错误一:错记“<<”与“+”的优先级 因为“<<”和“>>”相当于乘除2^N,所以容易误认为它们的优先级高于加减运算,其实不然。当把它们跟加减法一起用的时候一定要注意。比如计算n*5:
result = n << 2 + n; 这样就错了,应该用括号:
result = (n << 2) + n; 错误二:“==”误写为“=”
这是一个比较低级却又难以发现的错误。说它低级是因为它属于再基本不过的语法问题;而它之所以难以发现是因为它不会产生编译错误,唯有在调试过程中跟踪执行才会发现。通常它导致的后果是某一个条件判断失效或者进一步导致死循环,比如:
if (rect.top = rect.bottom) { MessageBox(hwnd, "Invalid rectangle!", NULL, MB_OK | MB_ICONERROR); } 因为条件判断误写成了赋值,上面的判断将永远为真,除非rect.bottom为零。
错误三:头文件重复包含
当你的工程越来越庞大时,头文件的管理也麻烦起来。经常遇到这样的情况:在编译一个源文件时,发现因为没有包含某个头文件而导致“符号未定义”之类的错误,于是你加入了这个头文件,可是这个头文件中又包含另外一个头文件,而那个头文件原先已经加在源文件中了,结果产生了“符号重定义”错误,这样你又不得不把这个重复包含的文件去掉……
为了避免出现“符号重定义”错误,可以采取条件编译技术。在创建头文件时,首先为这个头文件定义一个唯一的标识(假设是_SOME_SYMBOL_),然后在头文件的开头及结尾加上几行代码,像下面这样:
#ifndef _SOME_SYMBOL_ #define _SOME_SYMBOL_
....(头文件代码)
#endif 第一行语句判断是否定义了符号_SOME_SYMBOL_,如果没有,说明本次编译尚未扫描过这个头文件,于是编译正常进行,并且定义符号_SOME_SYMBOL_,以标明文件已被扫描过一次;反之,如果文件已被包含过一次,_SOME_SYMBOL_就有了定义,于是条件编译语句使编译器跳过整个文件。
如果所有的头文件都这样处理,就可以大量减少出现“符号重定义”错误的机率。
错误四:指针未初始化
对于一个熟练的程序员来说,这决对是一个不该犯的错误。不过,有些初学者确实经常被这个问题弄胡涂。比如,曾见过有人这样写:
int *p; *p = 0; DOS下,这将有可能导致死机;WINDOWS下将导致一个非法操作。
切记,使用指针前一定要初始化,使它指向一个确实分配了的空间!!!
错误五:使用已释放了的指针
最常出现在释放链表时。初学者容易这样写:
while (p) { delete p; p = p->next; } 这样是很危险的。正确的方法是:
while (p) { q = p->next; delete p; p = q; } 错误六:printf()/scanf()中类型不匹配
虽然WINDOWS下一般不用这两个函数了,但是与之类似的sprintf()/sscanf()和fprintf()/fscanf()还是经常使用的。
如果格式字串中说明的变量类型与后面的参数列表不一致,printf()将导致输出结果混乱,scanf()有可能导致程序执行结果不稳定,甚至导致非法操作。
初学者或许会以为类型不一致也无所谓,因为C语言可以自动进行类型转换。这种想法是错误的。类型转换是在编译时已知原类型和所需类型时由编译器产生代码来完成的,而格式字串对编译器来说只是一般的字串,编译器并不理解其中的含义,也就无法知道其中的类型信息;另一方面,从printf()/scanf()函数内部,虽然可以理解格式字串,但却无法知道后面变量表中的各变量的类型,对printf()/scanf()内部来说,变量表只呈现为一段连续的单元字节,唯一可知的是这段连续单元的起始地址。
|