2

我正在使用“使用 C++ 的编程原理和实践”这本书来学习编程,其中一个练习是使用 while 循环遍历字符 az。

现在,我以前用 C++ 和其他语言编程过,所以我决定尝试使用尽可能少的行(同时仍然使用 while 循环)。然而,这伴随着我的输出成本有点混乱。

代码:

#include <iostream>
int main(){
    char ch = 'a';
    while(ch <= 'z')
        std::cout << ch << '\t' << (int) ch++ << std::endl;
    return 0;
}

输出:

b   97
c   98
d   99
e   100
...
x   119
y   120
z   121
{   122

现在我确实意识到这可以用 for 循环代替,我也这样做了(它有效)。但我仍然不明白这段代码有什么问题,这真的让我很烦。

看起来好像我已经告诉它输出“ch+1”,因为它在应该打印“a”的地方打印出“b”。直到 ch 的整数值被放入输出流(后增量)之后才完成增量。即使我早些时候增加了它,至少打印的字符和它们的整数值应该对应。

关于为什么此代码不起作用的任何想法?

4

4 回答 4

5

调用的顺序operator<<是明确指定的,但它们的操作数被评估的顺序不是。

的增量ch可能发生在您输出ch“第一次”之前或之后,并且由于交错的读/写操作,仅仅运行这个程序是未定义的:

[2003: 1.9/12]:完整表达式是不是另一个表达式的子表达式的表达式。[..]

[2003: 1.9/16]:每个完整表达式的评估完成时都有一个序列点。

[2003: 5/4]:除非另有说明,否则未指定单个运算符的操作数和单个表达式的子表达式的求值顺序,以及副作用发生的顺序。在前一个和下一个序列点之间,一个标量对象的存储值最多只能通过表达式的评估修改一次。此外,只能访问先验值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,都应满足本段的要求;否则行为未定义。


相反,要明确:

std::cout << ch << '\t' << int(ch) << std::endl;
++ch;

您的编译器应该警告您有关您的代码。这并不表示您没有将诊断设置为有用的级别。

使用 GCC,使用-Wall -Wextra -std=c++98 -pedantic(或-Wall -Wextra -std=c++0x -pedantic用于 C++0x)。

于 2011-08-14T15:05:16.873 回答
2

简短的回答是您有一些未定义的行为,因为您ch在同一个表达式中通过单独的子表达式修改和使用变量的值。

正确的做法是使用最实用的循环来完成手头的任务:

#include <iostream>
int main(){
    for(char ch = 'a'; ch <= 'z'; ++a){
        std::cout << ch << '\t' << ch+0 << std::endl;
    }
}
于 2011-08-14T15:00:25.943 回答
2

您代码中的 ch++ 将首先被评估。一个更具可读性和正确性的版本是:

#include <iostream>
int main(){
    char ch = 'a';
    while(ch <= 'z') {
        std::cout << ch << '\t' << int(ch) << std::endl;
        ++ch;
    }
    return 0;
}
于 2011-08-14T15:01:05.823 回答
1

当您在一个命令或表达式中使用一个变量两次时,一次使用 ++(或 --),一次不使用,您会得到未定义的行为。

而是使用:

while(ch <= 'z')
{
   std::cout << ch << '\t' << (int) ch << std::endl;
   ch++;
}
于 2011-08-14T15:03:18.297 回答