当前位置:嗨网首页>书籍在线阅读

15-赋值、比较和可能犯的错误

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

5.1.13 赋值、比较和可能犯的错误

不要混淆等于运算符(= =)与赋值运算符(=)。下面的表达式问了一个音乐问题——musicians是否等于4?

musicians == 4 // comparison

该表达式的值为true或false。下面的表达式将4赋给musicians:

musicians = 4 // assignment

在这里,整个表达式的值为4,因为该表达式左边的值为4。

for循环的灵活设计让用户很容易出错。如果不小心遗漏了= =运算符中的一个等号,则for循环的测试部分将是一个赋值表达式,而不是关系表达式,此时代码仍是有效的。这是因为可以将任何有效的C++表达式用作for循环的测试条件。别忘了,非零值为true,零值为false。将4赋给musicians的表达式的值为4,因此被视为true。如果以前使用过用=判断是否相等的语言,如Pascal或BASIC,则尤其可能出现这样的错误。

程序清单5.10中指出了可能出现这种错误的情况。该程序试图检查一个存储了测验成绩的数组,在遇到第一个不为20的成绩时停止。该程序首先演示了一个正确进行比较的循环,然后是一个在测试条件中错误地使用了赋值运算符的循环。该程序还有另一个重大的设计错误,稍后将介绍如何修复(应从错误中吸取教训,而程序清单5.10在这方面很有帮助)。

程序清单5.10 equal.cpp

// equal.cpp -- equality vs assignment
#include <iostream>
int main()
{
    using namespace std;
    int quizscores[10] =
        { 20, 20, 20, 20, 20, 19, 20, 18, 20, 20};
    cout << "Doing it right:\n";
    int i;
    for (i = 0; quizscores[i] == 20; i++)
        cout << "quiz " << i << " is a 20\n";
// Warning: you may prefer reading about this program
// to actually running it.
    cout << "Doing it dangerously wrong:\n";
    for (i = 0; quizscores[i] = 20; i++)
        cout << "quiz " << i << " is a 20\n";
    return 0;
}

由于这个程序存在一个严重的问题,读者可能希望了解它,而不是真正运行它。下面是该程序的一些输出:

Doing it right:
quiz 0 is a 20
quiz 1 is a 20
quiz 2 is a 20
quiz 3 is a 20
quiz 4 is a 20
Doing it dangerously wrong:
quiz 0 is a 20
quiz 1 is a 20
quiz 2 is a 20
quiz 3 is a 20
quiz 4 is a 20
quiz 5 is a 20
quiz 6 is a 20
quiz 7 is a 20
quiz 8 is a 20
quiz 9 is a 20
quiz 10 is a 20
quiz 11 is a 20
quiz 12 is a 20
quiz 13 is a 20
...

第一个循环在显示了前5个测验成绩后正确地终止,但第二个循环显示整个数组。更糟糕的是,显示的每个值都是20。更加糟糕的是,它到了数组末尾还不停止。最糟糕的是,该程序可能导致其他应用程序无法运行,您必须重新启动计算机。

当然,错误出在下面的测试表达式中:

quizscores[i] = 20

首先,由于它将一个非零值赋给数组元素,因此表达式始终为非零,所以始终为true。其次,由于表达式将值赋给数组元素,它实际上修改了数据。最后,由于测试表达式一直为true,因此程序在到达数组结尾后,仍不断修改数据。它把一个又一个20放入内存中!这会带来不好的影响。

发现这种错误的困难之处在于,代码在语法上是正确的,因此编译器不会将其视为错误(然而,由于C和C++程序员频繁地犯这种错误,因此很多编译器都会发出警告,询问这是否是设计者的真正意图)。

警告: 不要使用=来比较两个量是否相等,而要使用= =。

和C语言一样,C++比起大多数编程语言来说,赋予程序员更大的自由。这种自由以程序员应付的更大责任为代价。只有良好的规划才能避免程序超出标准C++数组的边界。然而,对于C++类,可以设计一种保护数组类型来防止这种错误,第13章提供一个这样的例子。另外,应在需要的时候在程序中加入保护措施。例如,在程序清单5.10的循环中,应包括防止超出最后一个成员的测试,这甚至对于“好”的循环来说也是必要的。如果所有的成绩都是20,“好”的循环也会超出数组边界。总之,循环需要测试数组的值和索引的值。第6章将介绍如何使用逻辑运算符将两个这样的测试合并为一个条件。