为什么字符数组必须以空字符结尾?

5
为什么char数组必须以空字符结束?我必须为每个char数组添加空字符吗?它们似乎被同样处理。

1
一些编程语言使用“Pascal风格”的字符串,即长度+字符。C语言使用NUL。 - stark
4个回答

10

字符数组不一定需要以null结尾(不依赖此的标准库函数包括memcpymemmovestrncpy(这个最近被错误命名)、printf使用正确的格式字符串)。

一个以NUL结尾的字符串 (NTCS) 的定义需要以NUL结尾。这是C标准库字符串处理实用程序所期望的格式,并且是大多数C程序使用的约定(在C++中,通常使用std::string)。


所以这就像是一种约定!但为什么要这样做呢?不把它设为非空终止符会更容易吗?我不明白。我读到过,例如当我打印一个空终止数组时,编译器会知道何时停止打印。因此,这个空字符在某种程度上有用,可以防止打印出其余的垃圾字符。谢谢! - Alex Dannk
@Alex 在你提出的设计中,所有字符串都必须具有相同的长度。 - David Heffernan
@Alex,替代结束标记(如NUL)的方法是使用长度字段。实际上,使用哨兵通常简化算法,并且它允许您不必为所有字符串支付开销而不必具有任意最大大小(是的,在选择一个一字节或两字节大小字段之间的时间可能很难,内存很紧张,但限制自己在255个字符以内?我认为后者会被选择)。 - AProgrammer
@AlexDannk 是的,空字符的作用是让处理字符串的函数可以检查每个字符,当它们找到一个空字符时,就知道它们已经到达了字符串的末尾。 - bames53

4
在C语言中,如果你有一个指向数组的指针,那么没有办法确定该数组的长度。正如@AProgrammer所指出的那样,设计者可以将其保留下来,并强制程序员跟踪所有字符数组的长度。然而,这会使C语言中的文本处理变得更加困难。
因此,语言设计者采用了一种约定,允许通过空字符的存在来推断字符串的长度。
例如,考虑strcpy函数:
char *strcpy(char *destination, const char *source);

在C语言中无法确定指针destinationsource所指向的数组长度。所以,在没有哨兵值表示字符串结尾的情况下,唯一的解决方法就是传递额外的参数来指示source字符串的长度。

当然,在现代安全考虑方面,已经引入了带有缓冲区长度参数的字符串处理函数。但是,在空字符结尾的字符串被发明时,计算机领域的情况大不相同。


是的,但是我的意思是,如果我定义了一个char数组arr[2]={'h','i'},我猜编译器会知道arr的长度。 - Alex Dannk
@AlexDannk 是的,那是真的。但是如果所有字符串都被限制为具有相同的长度,那显然是没有用的。 - David Heffernan
抱歉!我不明白你的意思。你说它有助于知道数组的长度。但编译器已经知道任何数组的长度,所以我不认为它有用。 - Alex Dannk
@Alex 但是在处理文本时,您不使用数组,而是使用指向数组的指针。然后您就不知道数组的长度。 - David Heffernan
1
@AlexDannk:当你把那个字符串传给别人时会发生什么?编译器无法传递数组的size;当传递到函数时,数组会衰减为指针。大小信息丢失了。 - Nicol Bolas

1

只有当您想将其用作字符串时才需要注意。然后,所有的C/C++字符串函数都会在末尾搜索空字符,如果没有找到,它们将继续搜索,最终导致应用程序崩溃。

如果您只打算将字符数组用作字符数组,从不将其引用为字符串,则没有问题。这就像一个整数数组一样。


这个程序是怎么样的呢?char arr[2]={'h','i'}; cout << arr; 既然编译器找不到空字符来结束,为什么它不会崩溃呢? - Alex Dannk
@Alex - 有时候它似乎可以工作,但结果确实是未定义的。我们不知道数组后面的下一个字节的值 - 它可能只是零。在这种情况下,显示的值看起来很好。如果不是这样,程序可能会显示垃圾或崩溃。 - Bo Persson

0
通常情况下没有理由这样做,但你必须知道,根据定义,每个字符串都是一个带有空终止符的字符数组。如果你的字符数组表示一个字符串,那么如果省略了空终止符,每个与C字符串一起使用的函数将无法返回正确的值或者行为与预期不同。
然而,char像int、float或double一样是一种类型,因此你可以自由地创建char数组,而不需要它们以空终止符结尾。

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