我对 C++ 非常缺乏经验,我编写了以下代码来了解字符和字符串的工作原理。
#include "stdio.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
char asdf[] = "hello";
char test[5] = {'h','e','l','l','o'};
cout << test;
}
我本以为它会输出“hello”,但我却得到了“hellohello”,这让我很困惑。我做了一些实验:
如果我将 asdf 更改为另一个不同长度的字符串,它会正常输出“hello”。 如果我更改测试中的字符数量,它会正常输出“hello”。
我以为只有当两者长度相同时才会发生这种情况,但当我将它们都改为“hell”时,它似乎正常输出“hell”。
让事情变得更加困惑的是,当我让一位 friend 在他们的计算机上运行这段代码时,它输出了“hello”,然后是一个随机字符。
我正在 Ubuntu 上运行全新安装的代码块。有人知道这里发生了什么吗?
最佳答案
这是未定义的行为。
原始 char*
或 char[]
C 和 C++ 中的字符串必须是 NULL-terminated .也就是说,字符串需要以 '\0'
结尾。特点。你的test[5]
不这样做,所以打印输出的函数在最后一个 o
之后继续,因为它仍在寻找 NULL 终止。
由于字符串在 stack 上的存储方式(堆栈通常向较低地址增长),它遇到的下一个字节是asdf[]
的字节。 ,您分配了 "hello"
.这就是内存布局的实际样子,箭头表示内存地址(想想指针)增加的方向:
---->
+-------------------
|hellohello\0 ...
+-------------------
\_ asdf
\_ test
现在在 C++ 和 C 中,字符串文字如 "hello"
隐式以 NULL 终止,因此编译器写入一个隐藏的 '\0'
在字符串的末尾后面。输出函数继续逐字符打印 asdf 的内容,直到到达隐藏的 '\0'
。然后它停止了。
如果您要删除 asdf
,您可能会在第一个 hello
之后看到一些垃圾然后是段错误。但这是未定义的行为,因为您正在读取 test
的范围。大批。这也解释了为什么它在不同系统上的行为不同:例如,一些编译器可能决定以不同的顺序在堆栈上布置变量,因此在您 friend 的系统上,test
实际上在栈上较低(记住,在栈上较低意味着在较高地址):
---->
+-------------------
|hello\0hello ...
+-------------------
\_ test
\_ asdf
现在当你打印 test
的内容时, 它将打印 hello
逐个字符,然后继续读取内存直到 \0
被发现。 ...
的内容高度特定于所用的体系结构和运行时,甚至可能是月相和一天中的时间(不完全是认真的),因此在您 friend 的机器上它会打印一个“随机”字符然后停止。
您可以通过添加 '\0'
来解决此问题或 0
给你的test
数组(您需要将大小更改为 6)。但是,使用 const char test[] = "hello";
是解决这个问题的最明智的方法。
关于c++ - C++中字符数组的意外输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40057292/