C中数组中的终止NULL
我有一个简单的问题。
为什么有必要考虑字符数组(或简称字符串)中的终止空值而不是整数数组。 所以,当我想要一个字符串来容纳20个字符时,我需要声明char string[21];
。 当我想声明一个包含5位数的整数数组时,则为int digits[5];
足够。 这是什么原因?
如果您不想使用NULL
则不必终止带有NULL
的char
数组,但是当使用它们来表示字符串时,您需要这样做,因为C使用以null结尾的字符串来表示其字符串。 当您使用对字符串进行操作的函数(例如strlen
for string-length或使用printf
输出字符串)时,这些函数将读取数据直到遇到NULL
。 如果不存在,那么您可能会遇到缓冲区溢出或类似的访问冲突/分段故障问题。
简而言之:这就是C代表字符串数据的方式。
字符串(或字符数组)末尾需要空终止符,因为:
- 大多数标准库字符串函数都需要null字符。 它放在那里代替传递一个显式的字符串长度(虽然有些函数需要它。)
- 按照设计,
NUL
字符(ASCII 0x00)用于指定字符串的结尾。 因此,当从ASCII文件或流中读取时,它也被用作EOF字符。
从技术上讲,如果您使用自己的编码函数进行自己的字符串操作,则不需要空终止符; 你只需要跟踪字符串的长度。 但是,如果你使用任何标准化的东西,它会期待它。
按照惯例,C字符串以ascii nul字符结尾。 (这实际上与NULL不同。)
如果您愿意,可以使用nul字节开始字符串,或者在字符串中间随机包含nul字节。 然后,您将需要自己的库。
所以答案是:所有数组都必须为其所有元素分配空间。 你的“20个字符串”只是一个21个字符的字符串,包括nul字节。
原因是它是原始实现者的设计选择。 以null结尾的字符串为您提供了一种将数组传递给函数而不传递大小的方法。 对于整数数组,您必须始终传递大小。 Ints语言的惯例不再是你可以重写c中的每个字符串函数而不使用null终止符,但你总是必须跟踪你的数组大小。
字符串中空终止的目的是使解析器知道何时停止迭代字符数组。
因此,当您使用带有%s
格式字符的printf
时,它基本上是这样做的:
int i = 0; while(input[i] != '\0') { output(input[i]); i++; }
这个概念通常被称为哨兵 。
这不是关于声明一个更大的数组,而是关于我们如何选择在C中定义字符串。
按照惯例,C字符串被认为是由最终NUL字符终止的一系列字符,如您所知。 这是以解释"string literals"
的forms融入语言,并被所有标准库函数(如strcpy
和printf
等)采用。每个人都同意这就是我们将如何在C中执行字符串,并且该字符是那里告诉字符串停止的那些function。
反过来看你的问题,你在整数数组中没有做类似事情的原因是因为你有另外一种方法可以知道数组有多长 – 你用它来传递一个长度,或者它有一些假设的大小。 字符串可以在C中以这种方式工作,或者有一些其他结构,但它们没有 – 贝尔实验室的人决定“字符串”将是一个标准的字符数组,但总是会终止NUL所以你我知道它在哪里结束了。 (那时候这是一个很好的权衡。)
将字符数组设为21个元素并非绝对必要。 只有遵循(几乎总是假定的)约定,二十个字符后跟一个空终止符才有必要。 整数和其他数组中的终结符通常没有这样的约定。
由于与其他约定相比如何实现C字符串的技术原因
实际上 – 如果你不想,你不必NUL终止你的字符串! 唯一的问题是你必须重写所有的字符串库,因为它们依赖于它们。 如果您想要使用它们的function,这只是按照库所期望的方式进行的。
如果我想和她约会,就像我必须在午夜将你的女儿带回家一样 – 只是与图书馆(或者在这种情况下,父亲)达成协议。