【问题标题】:I don't understand how my compiler got this output我不明白我的编译器是如何得到这个输出的
【发布时间】:2020-02-09 20:30:27
【问题描述】:

请注意,我使用的是 Turbo C++ 编译器,因为我们应该只为学校教学大纲学习 Turbo C++。这就是为什么在这种情况下,cout 语句是从右到左计算的。

计划

#include <iostream.h>
#include <string.h>

void func(char *s, char t[]) {
    strcpy(t, "Have fun");
    s = "Be\0Cool";
    cout << s[0] << ++s << s++ << --s << strupr(s+2) << ++s << s++ << s;
}

int main() {
    char x[] = "Hello World!!!", y[] = "Hello World";
    func(x, y);
    cout << x << y;
    return 0;
}

输出

CCOOLeeOOLBeBeBeBeBeHello World!!!玩得开心


我觉得输出应该是:

CeeOOLBeBeHello World!!!玩得开心

因为在cout 语句的++s 部分(第二个位置),指针位于字符串s 的索引3,因此只应打印“Cool”。相反,正在打印“酷”。为什么会这样?

【问题讨论】:

  • 未定义的行为以及strupr 转换整个字符串的事实。
  • because we are supposed to learn only Turbo C++ for our school syllabus 太糟糕了。
  • "Turbo C++" == "浪费你的时间"。该编译器永远将与您未来的生活相关,并且它教给您的(不是 C++)语言是您必须学习的东西。不要把你的时间浪费在那些过时的废话上......
  • @Sujit 它确实改变了字符串。它不会神奇地在以太中的某个地方创造空间,转换为大写并存储在那个空间中,然后返回一个指向相同的指针。随之而来的内存泄漏将是可怕的。它就地转换。返回的结果 char* 便于在表达式中使用。无论如何,cout 链调用 UB,简单明了。
  • @Sujit 编写这种依赖于未定义行为的代码没有任何意义,尝试理解它更没有意义。 使用多个语句编写正确的代码。

标签: c++ turbo-c++


【解决方案1】:

使用 Visual Studio 2019 进行测试

出于比较目的,在 Visual Studio 2019 (DEBUG) 中,如果我们进行必要的更改来编译代码,则程序会崩溃,因为我们尝试修改常量字符串 ("Be\0Cool")。

如果我们做额外的改变来避免崩溃(通过使用本地数组),输出是:

CCoOLeCoOLOLCoOLBeCoOLHello World!!!玩得开心

如果我们将cout &lt;&lt; s[]…; 行拆分为对cout 的多个调用(每个&lt;&lt; 之前一个),那么输出将是:

BeeeCOOLCOOLHello World!!!玩得开心

或者如果我们在每个输出后添加一行,我们得到:

B
e
e
e
COOL


COOL
Hello World!!!
Have fun

尝试理解 Turbo C++ 的输出

如果我们然后将每个对 cout 的调用反转为从最后一个开始(即cout &lt;&lt; s&lt;&lt; endl;)并以第一个结束(cout &lt;&lt; s[0] &lt;&lt; endl),那么我们得到:

Be
Be

OOL
e
e
COOL
C
Hello World!!!
Have fun

如果我们手动编写,从倒数第三行开始,然后是最后两行,没有空格,我们得到:

CCOOLeeOOLBeBeBeBeBeHello World!!!玩得开心

这正是你得到的输出。

因此,Turbo C++ 似乎从右到左计算每个表达式。

有关编译(和运行)所需更改的说明

  • &lt;iostream.h&gt; 不可用,所以我必须改用 &lt;iostream&gt;
  • 必须在顶部添加#define _CRT_SECURE_NO_WARNINGS,因为某些函数不安全(默认情况下不会编译)。
  • using namespace std; 以避免对代码进行更多更改。
  • s = (char *)"Be\0Cool"; 中添加强制转换,以便编译该行。
    • 这会导致崩溃,因为数据是不变的,我们会尝试对其进行修改。
  • 删除演员表,改为写char data[] = "Be\0Cool"; s = data;
    • 程序运行但输出为CCoOLeCoOLOLCoOLBeCoOLHello World!!!Have fun
    • 事实上,这是未定义的行为。它恰好是实际输出。

未定义的行为

有些东西没有被标准定义,因此不需要以某种方式工作。好吧,正如预期的那样,如果不支持只读内存,它就像读写内存一样工作。

对于评估的顺序,常见的可能性是:

  • 从左到右
  • 从右到左
  • 哪个更好

此外,由于一个变量被多次修改,s 的值在评估期间和之后没有定义。容易记住的规则是避免在一个表达式中多次修改同一个变量。

关于 strupr

该函数将字符串修改为终止空字符。在您的情况下,它会在调用时将 s 具有的任何值的每个字母转换为大写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 2012-05-23
    • 1970-01-01
    相关资源
    最近更新 更多