1. = 不等于 ==
从 Algol 派生出来的语言,如 Pascal 和 Ada,用 := 表示赋值而用 = 表示比较。而 C 语言则是用 = 表示赋值而用 == 表示比较。这是因为赋值的频率要高于比较,因此为其分配更短的符号。此外,C 可以多重赋值(如 a = b = c),并且可以将赋值嵌入到一个大的表达式或者语句中。这种便捷导致了一个潜在的问题:需要用比较的地方却写成了赋值。下面的语句看起来好像是要检查 x 是否等于 y :
if ( x = y )
foo();
而实际上是将 y 的值赋值给 x ,并检查结果是否非零。再看看下面的一个希望跳过空格、制表符和换行符的循环:
while ( c == ' ' || c = '\t' || c == '\n' )
c = getc(f);
在应该与 '\t' 进行比较的地方程序员错误地使用了 =,而不是==。这个“比较”实际上是将'\t' 赋给 c,然后判断 c 的(新的)值是否为零。因为 '\t' 不为零,所以这个“比较”一直为真,因此这是一个死循环。
一些编译器会对形如 e1 = e2 的条件给出一个警告以提醒用户。当你确实需要对一个变量进行赋值,然后再检查变量是否“非零”时,为了避免这种警告信息,应显式给出比较符。也就是将:
if ( x = y )
foo();
改写为:
if ( ( x = y ) != 0 )
foo();
2. 多字符符号
一些 C 符号,如 /、* 或 =,只有一个字符。还有些 C 符号,如 /* 、 == 或标识符,具有多个字符。当编译器遇到紧连在一起的 / 和 * 时,它必须决定是将这两个字符识别为两个符号还是一个单独的符号。C 语言标准规定:“如果一个字符被识别为符号,则应该包含下一个字符看看包含此字符后构成的字符串是否仍然可以构成符号,如果可以则继续包含下一个字符,一直到不能构成符号为止。”。因此,如果 / 是符号的第一个字符,并且 / 后面紧随着一个 *,则这两个字符构成注释符开始标记。下面的语句看起来像是将 y 的值设置为 x 的值除以 p 所指向的值:
y = x/*p /* p 指向除数 */;
实际上,因为 /* 是注释符开始标记,因此编译器会简单地“吞噬”程序文本,直到 */ 出现为止。换句话说,这条语句仅仅把 y 的值设置为 x 的值,而根本没有看到 p。我们应该将这条语句改为:
y = x / *p /* p 指向除数 */;
或者:
y = x / (*p) /* p指向除数 */;
3. else 问题
考虑下面的程序片断:
if ( x == 0 )
if ( y == 0 )
error();
else {
z = x + y;
f(&z);
}
写这段程序的程序员的目的明显是想将情况分为两种:x == 0 和x != 0。在第一种情况中,如果 y == 0,则调用 error()。第二种情况中,程序执行 z = x + y; 和 f(&z); 。
然而, 这段程序的实际效果却大为不同。其原因是 else 总是与离它最近的 if 相关联。上面那段代码其实等价于:
if ( x == 0 ) {
if ( y == 0 )
error();
else {
z = x + y;
f(&z);
}
}
也就是说,当 x != 0 发生时什么也不做。如果要达到我们想要的效果,应该改成:
if ( x == 0 ) {
if ( y == 0 )
error();
} else {
z = z + y;
f(&z);
}
4. 表达式求值顺序
一些运算符以一种已知的、特定的顺序对其操作数进行求值。但另一些则不是。例如下面的表达式:
a < b && c < d
C 标准规定 a < b 首先被求值。如果 a 确实小于 b,c < d 必须紧接着被求值以计算整个表达式的真假性。但如果 a 大于或等于 b,则 c < d 根本不会被求值。而对 a < b 求值时,到底是先取 a 的值,还是先取 b 的值,标准并没有定义。
C 中只有四个运算符(&&、||、?: 和 ,)指定了求值顺序。&& 和 || 最先对左边的操作数进行求值,而右边的操作数只有在需要的时候才进行求值。而 ?: 运算符中的三个操作数中,先对最左边的进行求值,然后根据它的值决定到底应该求中间的操作数的值,还是求最右边的操作数的值。逗号运算符(,)的求值顺序为从左到右。
C 中所有其它运算符的操作数的求值顺序都是未定义的。特别要说的是,赋值运算符也没有对求值顺序做出任何保证。
出于这个原因,下面这种将数组 x 中的前 n 个元素复制到数组 y 中的方法是不可行的:
j = 0;
while ( j < n )
y[j] = x[j++];
因为标准没有保证 y[j] 在 j 增长之前被求值。到底 y[j] 先求值,还是 x[j++] 先求值是依赖编译器的!所以我们不应该这么写!另一种方案基于同样的原因也不可行:
j = 0;
while ( j < n )
y[j++] = x[j];
下面的代码才是正确的:
j = 0;
while ( j < n ) {
y[j] = x[j];
j++;
}
当然,也可以这么写:
for ( j = 0; j < n; j++ )
y[j] = x[j];
5. &&、|| 和 ! 运算符
C 规定 0 代表“假”,非零代表“真”。这些运算符返回 1 表示“真”而返回 0 表示“假”。&& 和 || 运算符如果可以通过左边的操作数确定整个表达式的真假性,就不会对右边的操作数进行求值。!10 返回 0,因为 10 非零;10 && 12 返回 1,因为 10 和 12 的值都不是 0;10 || 12 也是 1,因为 10 非零。这个表达式中的 12 不会被求值,因为左边的 10 就足够确定整个表达式为真。同理 :10 || f() 中的 f() 也不会被求值。
6. 下标从零开始
C 语言中,一个具有 n 个元素的数组中没有下标为 n 的元素,元素的下标是从 0 到n-1。下面的程序可能会崩溃:
int i, a[10];
for ( i = 1; i <= 10; i++ )
a = 0;
应该改成:
int i, a[10];
for ( i = 0; i < 10; i++ )
a = 0;
7. getchar 函数的返回值为整型(int)
请看以下程序:
#include <stdio.h>
int main( void )
{
char c;
while ( ( c = getchar() ) != EOF )
putchar(c);
return 0;
}
这段代码存在一个小小的,但已经足以致命的错误:c 被声明为字符型(char)而不是整型。这意味着 c 可能不能正确接收 EOF,从而导致程序不能退出!正确的写法是:将 char 改成int。
分享到:
相关推荐
《C语言程序设计》作为大多数理工科学生入门的第一门高级程序设计语言课程,在软件开发领域占据着极其重要的地位。由于大部分学生在接触该课程前缺乏编程经验,加之C语言编译器对语法的要求相对宽松,程序设计的自由...
C语言调试是C语言程序设计中非常重要的一步骤,对于初学者来说尤其重要。C语言调试常见错误主要可以分为两类:第一个类错误是编译时错误,第二个类错误是运行时错误。本文将对C语言调试常见错误进行分类和讲解,...
C语言程序设计常见错误总结分析 C语言是一种广泛使用的编程语言,但是在实际编程过程中,程序员经常会遇到各种错误。这些错误可能是语法错误、逻辑错误或运行错误,本文将对这些错误进行总结和分析。 语法错误是指...
C语言是一种功能强大且灵活的编程语言,它的灵活性使得程序员有更大的自由度来设计程序,但也正因为这种灵活性,初学者在编程过程中容易遇到各种错误。以下是一些C语言初学者常犯的错误及其解释: 1. **大小写混淆*...
标题为《C语言程序设计中常见错误的探讨》,此文章的主要内容是对在学习C语言程序设计过程中学生们易犯的错误进行探讨分析。文章开篇指出C语言程序设计这门课程在高校计算机课程中的重要地位,尤其在本科高校的...
C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活 给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。...
通过学习和避免这些常见错误,C++程序员可以提升代码质量,提高编程效率,减少调试时间,从而更快速地编写出高质量的代码。 在描述中,提到本书是C++编程领域的专家Stephen C. Dewhurst在长期教授C++课程和编写C++...
C语言编程常见错误小结 C语言作为一种功能强、使用方便灵活的编程语言,对初学者来说,经常会出现一些连自己都不知道错在哪里的小错误。本篇文章总结了C语言编程中常见的8种错误,旨在帮助初学者避免这些错误,节省...
"C语言常见错误——写给编程初学者" 通过对C语言的学习和实践,我们总结出了编程初学者容易犯的一些错误。这些错误可能看起来很简单,但是却容易被忽视,导致程序出错或无法运行。下面我们将详细地讲解这些错误。 ...
分析C语言编程中常见错误及解决办法 C语言是一种广泛使用的编程语言,具有强大的功能、灵活的语法和方便的使用方式。然而,在实际编程中,C语言也存在一些常见的错误,这些错误对编程的质量和效率有重要的影响。...
C语言常见错误提示 C语言是一种流行的编程语言,但是在编程过程中,开发者经常会遇到各种错误提示。这些错误提示可能会使开发者感到迷惑和困惑,但实际上它们都是可以避免的。本文总结了C语言编程时常见的错误提示...
keil-c语言编程常见错误分析.doc
【C语言程序设计:常见错误总结分析】 C语言是一种强大的编程语言,但初学者在编程过程中往往会遇到多种错误。这些错误通常分为三类:语法错误、逻辑错误和运行错误。 1. **语法错误**:这类错误是由于代码违反了...
总之,C语言编程中虽然存在诸多常见错误,但通过学习和实践,理解常见错误的类型和原因,就可以采用恰当的策略去解决它们。开发者应当在编程过程中细心谨慎,尽量避免上述错误的出现,从而提高编程效率和代码质量。
下面将详细讲解C语言的原理、屏幕界面程序设计、内存驻留程序设计以及应用技巧,并针对常见的编译错误进行深入分析。 C语言原理: C语言是一种强大的、低级别的编程语言,它的核心特性包括结构化编程、类型系统和...
C语言以其高效和灵活性被广泛应用于系统编程、嵌入式开发等领域。然而,C语言的这些特性也意味着程序员需要对内存管理、指针操作等有深入...本文通过详细的代码示例和解决方案,帮助读者识别和处理C语言中的常见错误。
C语言,作为一种底层且高效的编程语言,是实现编译器或解释器的常见选择。它允许直接操作内存,方便处理二进制数据,这对于构建语言的底层结构至关重要。郑钢的源代码可能会涵盖词法分析器(lexer)和语法解析器...