考虑以下计划:
#include <iostream>
int main()
{
int num=345;
std::cout<<"num " + num<<'\n';
}
当我运行此程序时,它显示F作为输出。怎么样?是否在这里执行指针运算?如果我使用 - 符号而不是+,则会出现空白输出。
答案 0 :(得分:14)
字符串文字"num "
为const char[5]
,它会衰减到您要添加偏移量的const char*
。
以下代码相当于您正在做的事情:
#include <iostream>
int main()
{
int num = 345;
const char* c_str = "num ";
std::cout << c_str + num << '\n';
}
A:您有未定义的行为,因为您正在访问数组范围之外的内存位置。你违反了记忆安全。
由于cout
只有在找到'\0
&#39;对于c-strings,你可以继续打印直到它。您无法知道该值何时会发生,因此您有未定义的行为,如 A 中所述。
答案 1 :(得分:7)
假设你有"num"
字符串。在内存中它可能看起来像,
0 1 2 3 4
[n][u][m][ ][\0]
打印时,它将用作指针。现在你为它添加了一个345的偏移量。
0 1 2 3 4 5 6 7 345
[n][u][m][ ][\0][?][?][?]....[F][?][?]
您的程序可能打印的不仅仅是F,它会在找到的第一个\0
上停止。这是未定义的行为,因为您的程序可以打印任何内容,并将访问无效的内存地址。
如果您的目标是打印整数,那么您可以编写
std::cout << "num" << num << std::endl;
答案 2 :(得分:6)
编译所有警告非常有益:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:6:25: warning: array subscript is above array bounds [-Warray-bounds]
std::cout<<"num " + num<<'\n';
^
请参阅here
基本上编译器告诉你,你已经在存储"num "
的底层数组上完成了指针算术。实质上"num "
是一个数组,用于存储该字符串文字所需的字符。当你对它进行算术运算时,它衰减到const char*
,然后你将指针地址加345。此内存地址位于已定义的数组之外,而您的特定计算机上这个值恰好是值F
。然而,这是未定义的行为,输出可能完全在另一台机器上。
这些编译器警告通常是错误的结果,所以注意编译器告诉你的内容通常很有价值。