c++ - 我不明白我的编译器是如何得到这个输出的
问题描述
请注意,我使用的是 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;
}
输出
CCOOLeeOOLBeBeBeHello World!!!玩得开心
我觉得输出应该是:
C Cool eeOOLBeBeBeHello World!!!玩得开心
因为在语句++s
部分(第二个位置),指针位于stringcout
的索引3s
处,所以应该只打印 'Cool'。相反,正在打印“酷”。为什么会这样?
解决方案
使用 Visual Studio 2019 进行测试
出于比较目的,在 Visual Studio 2019 (DEBUG) 中,如果我们进行必要的更改来编译代码,则程序会崩溃,因为我们尝试修改常量字符串 ( "Be\0Cool"
)。
如果我们进行额外的更改以避免崩溃(通过使用本地数组),则输出为:
CCoOLeCoOLOLCoOLBeCoOLHello World!!!玩得开心
如果我们将cout << s[]…;
line 拆分为多个调用cout
(在 each 之前一个<<
),那么输出将是:
BeeeCOOLCOOLHello World!!!玩得开心
或者,如果我们在每个输出后添加一行,我们会得到:
B
e
e
e
COOL
COOL
Hello World!!!
Have fun
试图理解 Turbo C++ 的输出
如果我们然后将每个对 cout 的调用反转为以最后一个(即cout << s<< endl;
)开始并以第一个(cout << s[0] << endl
)结束,那么我们得到:
Be
Be
OOL
e
e
COOL
C
Hello World!!!
Have fun
如果我们手动编写它,从倒数第三行开始,然后是最后两行,没有空格,我们得到:
CCOOLeeOOLBeBeBeHello World!!!玩得开心
这正是你得到的输出。
因此,Turbo C++ 似乎从右到左计算每个表达式。
关于编译(和运行)所需更改的说明
<iostream.h>
不可用,所以我必须<iostream>
改用。#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
在调用时将任何值的每个字母转换为大写。
推荐阅读
- wpf - 如何使用 WPF 中存在的元素创建网格样式
- c# - 为什么我的前馈神经网络不适用于不同的输入?
- typescript - 如何根据类属性声明 Typescript 类型?
- c++ - 为什么 char{} 和 char() 用作 char* 参数的临时变量?
- angular - Mat-table 多行内多行
- javascript - 单击时显示隐藏的第 n 个子项
- java - 从列表中的任何值获取键
- powerbi - 将 r 脚本添加到 power bi
- javascript - jQuery .val() 不返回选项标签的值
- java - 在android中的多个本地通知中设置操作,为广播接收器中的通知提供相同的ID