C语言中的空字符终止字符串

13

我非常担心在C中的字符串。我需要手动设置最后一个字符\0吗?如果我不手动设置,当我尝试调试代码并访问string1[257]时它就不是空的。我遇到了释放分配的字符串数组内存的问题,所以我认为这可能是原因。

char string1[257], string2[257];
scanf("%s", &string2);
string1[257] = '\0';
strncpy(string1, string2, 257);
string1[257] = '\0'; /* do I need to do that? */

14
请注意,如果您声明 char[257],索引范围将从 0 到 256。 - Aurelio De Rosa
5个回答

11

"Hello World!"这样的字符串字面量是以空字符结尾的,但是char数组不会自动以空字符结尾。

我一直遵循的通用原则是要格外小心,在字符串末尾分配'\0',除非这会导致性能问题。在这种情况下,我会特别小心地选择使用哪些库函数。


5
那是 \0(NUL),不是 NULL - Fred Foo
6
然而,NULL、0和'\0'具有不同的含义。不需要混淆它们,只是因为30年前设计的一种语言允许你这样做。 - John Zwinck
4
不一定,NULL 可以被定义为 ((void*)0)。无论如何,这些都是不应混淆的不同概念。 - Fred Foo
@larsmans - 啊,是的,NULL 可能是一个转换为 void*0,所以可能行不通。 - Michael Price
你关于数组的说法取决于它的初始化方式。考虑char str[4] = "test"和char str[]= "test"两种情况。 - Wiz

3

在使用字符串时,一定要小心分配足够的内存,请比较以下代码行的效果:

char s1[3] = "abc";
char s2[4] = "abc";
char s3[] = "abc";

这三种写法都被认为是合法的代码行(http://c-faq.com/ansi/nonstrings.htmlhttp://c-faq.com/ansi/nonstrings.html),但在第一种情况下,不足以容纳第四个空字符。s1将不像普通字符串那样运行,但s2和s3将正常。编译器会自动计算s3,并分配四个字节的内存。如果您尝试写入

s1[3] = '\0';

这是未定义的行为,你正在写入不属于s1的内存,并会产生奇怪的影响,甚至可能干扰malloc的后端信息,使释放内存变得困难。


2

"foo\nbar"这样的字面字符串总是被翻译为一个带有额外零字节的const char literal[]。(所以常量将有8个字节,第一个是f,最后一个是零)。

但是,在strncpy之后强制显式地将最后一个字节设置为0是正确的。

正如Aurelio De Rosa所指出的,对于数组[257],最后一个正确的索引是256。


2

是的,你需要这样做。并不是所有的函数都会为你放置空字符,而且根据我在strncpy的手册页中所读到的,它要求在src的前n个字符中必须有一个空字节。


2
strncpy是一个具有特殊语义的“特殊”函数。不幸的是,当人们只是在复制字符串时通常并不需要它。 - John Zwinck

1

这是绝对必要的吗?不是,因为当你调用scanfstrcpy(除了strncpy,如果超过大小需要手动放置零),它会自动为你复制空终止符。但是这样做有好处吗?实际上并没有,因为这些函数无论如何都会超出缓冲区的大小,所以并不能解决缓冲区溢出的问题。那么什么是最好的方法呢?使用C++和std::string

顺便说一下,如果你访问/写入string1[257],那将超出边界,因为你在一个大小为257的数组中访问/写入了第258个元素。(索引从0开始计数)


1
strncpy可能不会复制空终止符。请参见https://dev59.com/eXM_5IYBdhLWcg3wQQzw - Michael Price
哦,关于访问第258个元素的问题,我明白了。谢谢您先生。 - Arturs Vancans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接