C++ char数组null终止符位置

Joh*_*ney 13 c++ arrays char null-terminated

我是一名学习C++的学生,我试图理解空终止字符数组是如何工作的.假设我定义了一个char数组,如下所示:

char* str1 = "hello world";
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,strlen(str1)等于11,并且它以空值终止.

如果上面的char数组的所有11个元素都填充了字符"hello world",那么C++在哪里放置null终止符?它实际上是分配一个长度为12而不是11的数组,第12个字符是'\0'CPlusPlus.com似乎建议11中的一个需要'\0',除非它确实分配12.

假设我执行以下操作:

// Create a new char array
char* str2 = (char*) malloc( strlen(str1) );

// Copy the first one to the second one
strncpy( str2, str1, strlen(str1) );

// Output the second one
cout << "Str2: " << str2 << endl;
Run Code Online (Sandbox Code Playgroud)

这个输出Str2: hello worldatcomY?°g??,我假设是C++在指针指向的位置读取内存,char* str2直到它遇到它解释为空字符的内容.

但是,如果我这样做:

// Null-terminate the second one
str2[strlen(str1)] = '\0';

// Output the second one again
cout << "Terminated Str2: " << str2 << endl;
Run Code Online (Sandbox Code Playgroud)

Terminated Str2: hello world按预期输出.

但是写不str2[11]暗示我们在分配的内存空间之外写str2,因为str2[11]是第12个字节,但是我们只分配了11个字节?

运行此代码似乎不会导致任何编译器警告或运行时错误.在实践中这样做是否安全?使用malloc( strlen(str1) + 1 )而不是更好malloc( strlen(str1) )吗?

Jar*_*Par 13

在字符串文字的情况下,编译器实际上char\0元素保留了额外的元素.

// Create a new char array
char* str2 = (char*) malloc( strlen(str1) );
Run Code Online (Sandbox Code Playgroud)

这是新C程序员犯的常见错误.为a分配存储时,char*需要分配多少个字符+ 1来存储\0.不在此处分配额外存储意味着此行也是非法的

// Null-terminate the second one
str2[strlen(str1)] = '\0';
Run Code Online (Sandbox Code Playgroud)

在这里,你实际上写的是你分配的内存的末尾.分配X元素时,您可以访问的最后一个合法字节是内存地址偏移量X - 1.写入X元素会导致未定义的行为.它通常会起作用,但却是定时炸弹.

写这个的正确方法如下

size_t size = strlen(str1) + sizeof(char);
char* str2 = (char*) malloc(size);
strncpy( str2, str1, size);

// Output the second one
cout << "Str2: " << str2 << endl;
Run Code Online (Sandbox Code Playgroud)

在这个例子中,str2[size - 1] = '\0'实际上并不需要.该strncpy函数将使用null终止符填充所有额外的空格.这里只有size - 1元素,str1所以数组中的最后一个元素是不需要的,并将被填充\0

  • @JohnMahoney 我使用本地“size”有两个原因。首先是性能。`strlen` 函数虽然不昂贵,但时间复杂度为 O(N),并且由于字符串不会改变,因此没有理由多次运行它。`+ sizeof(char)` 部分主要是样式。`+ 1` 做同样的事情,我只是更喜欢更明确的 `sizeof(char)` 符号 (2认同)

Oli*_*rth 6

它实际上是分配一个长度为12而不是11的数组,第12个字符是'\ 0'吗?

是.

但是写不str2[11]暗示我们在分配的内存空间之外写str2,因为str2[11]是第12个字节,但是我们只分配了11个字节?

是.

使用malloc( strlen(str1) + 1 )而不是更好malloc( strlen(str1) )吗?

是的,因为第二种形式不够长,无法将字符串复制到.

运行此代码似乎不会导致任何编译器警告或运行时错误.

除了最简单的情况外,在所有情况下检测到这一点是一个非常困难的问题 所以编译器的作者根本就不费心.


std::string如果您正在编写C++,这种复杂性正是您应该使用而不是原始C风格字符串的原因.这很简单:

std::string str1 = "hello world";
std::string str2 = str1;
Run Code Online (Sandbox Code Playgroud)