尽管我热爱C和C ++,但我还是忍不住选择以null结尾的字符串:
- 在C之前存在长度前缀(即Pascal)的字符串
- 长度前缀的字符串允许进行恒定的时间长度查找,从而使几种算法更快。
- 前缀字符串的长度使导致缓冲区溢出错误更加困难。
- 即使在32位计算机上,如果允许字符串成为可用内存的大小,则带前缀前缀的字符串也只比以空终止的字符串宽3个字节。在16位计算机上,这是一个字节。在64位计算机上,4GB是一个合理的字符串长度限制,但是即使您希望将其扩展为机器字的大小,64位计算机通常也具有足够的内存,使得多余的7个字节属于null参数。我知道原始的C标准是为极差的机器(就内存而言)编写的,但是效率论点在这里并没有卖给我。
- 几乎所有其他语言(例如Perl,Pascal,Python,Java,C#等)都使用长度前缀的字符串。这些语言通常在字符串操作基准中胜过C,因为它们在使用字符串时效率更高。
- C ++使用
std::basic_string
模板对此进行了一些纠正,但是期望以null终止的字符串的纯字符数组仍然很普遍。这也是不完美的,因为它需要堆分配。 - 空终止的字符串必须保留一个字符(即null),该字符不能存在于字符串中,而长度前缀的字符串可以包含嵌入的null。
这些事情中,有几件事比C揭露的要新,因此C不必了解它们是有道理的。但是,在C出现之前,有几个很简单。为什么会选择空终止的字符串而不是明显更好的长度前缀?
编辑:由于上面我的效率问题上有人问了一些事实(并且不喜欢我已经提供的事实),因此它们源于以下几点:
- 使用空终止字符串的Concat需要O(n + m)的时间复杂度。长度前缀通常只需要O(m)。
- 使用空终止字符串的长度要求O(n)时间复杂度。长度前缀为O(1)。
- 长度和concat是迄今为止最常见的字符串操作。在几种情况下,以null终止的字符串可能更有效,但这种情况发生的频率要少得多。
从以下答案中可以看出,在某些情况下以null终止的字符串更有效:
- 当您需要切断字符串的开头并将其传递给某种方法时。即使允许销毁原始字符串,也不能真正在恒定时间内使用长度前缀来完成此操作,因为长度前缀可能需要遵循对齐规则。
- 在某些情况下,您只是逐个字符地遍历字符串,则可以保存CPU寄存器。请注意,这仅在您没有动态分配字符串的情况下才有效(因为您必须释放它,必须使用保存的CPU寄存器保存最初从malloc和friends获得的指针)。
以上都不是最常见的长度和连贯性。
下面的答案中还有一个断言:
- 您需要切断字符串的结尾
但这是不正确的-空终止和长度为前缀的字符串的时间相同。(以NULL结尾的字符串只是在您希望新的结尾处保留一个NULL,长度前缀只是从前缀中减去。)