为啥 C 中的字符串需要空终止?

Posted

技术标签:

【中文标题】为啥 C 中的字符串需要空终止?【英文标题】:Why do strings in C need to be null terminated?为什么 C 中的字符串需要空终止? 【发布时间】:2010-02-08 11:49:20 【问题描述】:

只是想知道为什么会这样。我渴望了解更多关于低级语言的知识,而且我只了解 C 的基础知识,这已经让我感到困惑了。

php 这样的语言在解释和/或解析字符串时会自动终止字符串吗?

【问题讨论】:

相关或可能重复:***.com/questions/1253291/… 刚刚也发现了这个:***.com/questions/2037209/… 表示文本的常用方法有两种: 1. 指定长度,后跟文本。或使用终止字符。许多数据库使用前者。要问自己一个问题,“如何确定字符串的结尾?” 【参考方案1】:

来自Joel's excellent article on the topic:

请记住字符串在 C 中的工作方式:它们由一堆字节组成,后跟一个空字符,其值为 0。这有两个明显的含义:

如果不移动它,就无法知道字符串的结尾(即字符串长度),寻找结尾处的空字符。 您的字符串中不能有任何零。因此,您不能在 C 字符串中存储任意二进制 blob,例如 JPEG 图片。 为什么 C 字符串会这样工作?这是因为发明了 UNIX 和 C 编程语言的 PDP-7 微处理器具有 ASCIZ 字符串类型。 ASCIZ 的意思是“以 Z(零)结尾的 ASCII。”

这是存储字符串的唯一方法吗?不,事实上,这是存储字符串的最糟糕的方式之一。对于非平凡的程序、API、操作系统、类库,你应该避免像瘟疫一样的 ASCIZ 字符串。

【讨论】:

太棒了,谢谢...还有哪些其他方法?谢谢。 C99 中是否有创建非 ASCIZ 字符串的标准方法? 这是杜撰的。我查看了 PDP-7 手册,但根本找不到任何提及 ASCIZ、null 甚至数据类型的内容。唯一提到 ASCII 是在输入程序数据中,而零在非字符串位置。有一个 TEXT 伪指令,但用户选择了分隔符。 * bitsavers.trailing-edge.com/pdf/dec/pdp7/… * bitsavers.org/pdf/dec/pdp7/PDP-7_AsmMan.pdf 事实上,PDP-8 ***页面上的示例程序显示了空终止字符串 en.wikipedia.org/wiki/PDP-8 的手动实现,但是我可以在 PDP-11 材料中找到参考。所以在我看来,ASCIZ 被添加到硬件中以支持 Unix 和 C 编程语言?【参考方案2】:

C 字符串是字符数组,而 C 数组只是指向内存位置的指针,即数组的 start 位置。但数组的长度(或结尾)也必须以某种方式表达;如果是字符串,则使用空终止。另一种选择是以某种方式将字符串的长度与内存指针一起携带,或者将长度放在第一个数组位置,或其他任何地方。这只是约定俗成的问题。

Java 或 PHP 等高级语言自动透明地将大小信息与数组一起存储,因此用户无需担心它们。

【讨论】:

【参考方案3】:

想想什么是内存:一个连续的字节大小的单元块,可以用任何位模式填充。

2a c6 90 f6

字符只是这些位模式之一。它作为字符串的含义由您处理它的方式决定。如果您查看内存的同一部分,但使用 integer 视图(或其他类型),您会得到不同的值。

如果你有一个变量,它是指向内存中一堆字符开头的指针,你必须知道那个字符串什么时候结束,下一段数据(或垃圾)开始。

示例

让我们看看内存中的这个字符串...

H e l l o , w o r l d ! \0 
^
|
+------ Pointer to string

...我们可以看到字符串逻辑上在! 字符之后结束。如果没有\0(或任何其他确定其结束的方法),我们如何知道在寻找内存时我们已经完成了该字符串?其他语言用 string 类型携带字符串长度来解决这个问题。

当我对计算机的基础知识有限时,我问了这个问题,而 this 是多年前会有所帮助的答案。我希望它也对其他人有所帮助。 :)

【讨论】:

【参考方案4】:

C 本身没有字符串的概念。字符串 简单的字符数组(或 unicode 等的 wchars)。

由于这些事实,C 无法检查字符串的长度,因为没有“mystring->length”,因此没有在某处设置长度值。找到字符串结尾的唯一方法是遍历它并检查 \0。

C 有一些字符串库,它们使用类似的结构

struct string 
    int length;
    char *data;
;

消除对 \0 终止的需要,但这不是标准 C。

C++、PHP、Perl 等语言都有自己的内部字符串库,这些库通常有一个单独的长度字段,可以加速某些字符串函数并消除对 \0 的需求。

其他一些语言(如 Pascal)使用称为(令人惊讶的)Pascal String 的字符串类型,它将长度存储在字符串的第一个字节中,这就是这些字符串长度限制为 255 个字符的原因。

【讨论】:

【参考方案5】:

因为在 C 中,字符串只是通过指向第一个字符的指针访问的字符序列。

指针中没有空间来存储长度,因此您需要一些指示字符串末尾的位置。

在 C 中,它决定用空字符表示。

例如,在 pascal 中,字符串的长度记录在指针前面的字节中,因此 pascal 字符串的最大长度为 255 个字符。

【讨论】:

【参考方案6】:

这是一个约定 - 可以用另一种算法来实现它(例如缓冲区开头的长度)。

在诸如汇编程序之类的“低级”语言中,很容易有效地测试“NULL”:与跟踪长度计数器相比,这可能更容易决定使用 NULL 终止的字符串。

【讨论】:

【参考方案7】:

它们需要以空值终止,以便您知道它们的长度。是的,它们只是字符数组。

像 PHP 这样的高级语言可能会选择对您隐藏空终止符或根本不使用它 - 例如,它们可能会保留一个长度。由于涉及的开销,C 不会那样做。高级语言也可能不会将字符串实现为 char 数组 - 例如,它们可以(并且有些确实)将它们实现为 char 数组列表。

【讨论】:

【参考方案8】:

在 C 中,字符串由分配在连续内存块中的字符数组表示,因此必须有一个指示块结束的指示符(即空字符),或者一种存储长度的方法(比如以长度为前缀的 Pascal 字符串)。

在 PHP、Perl、C# 等语言中,字符串可能有也可能没有复杂的数据结构,因此您不能假设它们有空字符。作为一个人为的示例,您可以使用一种表示字符串的语言,如下所示:

class string

   int length;
   char[] data;

但您只能将其视为没有长度字段的常规字符串,因为这可以由语言的运行时环境计算,并且仅由它在内部用于正确分配和访问内存。

【讨论】:

【参考方案9】:

它们是空终止的,因为很多标准库函数都希望它们是空终止的。

【讨论】:

还因为这就是 C 语言规范所说的字符串文字的编码方式。 @Stephen C,只有你这么说!很重要的原因!愚蠢的 C 字符串...我想要一个带有“pascal 字符串”的 C、libc 和字符串文字。

以上是关于为啥 C 中的字符串需要空终止?的主要内容,如果未能解决你的问题,请参考以下文章

C ++中的非空终止字符数组

C 标准库 - string.h之strstr使用

C ++:为啥读取时空格总是终止字符串?

C ++在固定大小9的右填充空终止字符数组中找到第一个空格的最快方法

访问 std::string 中的空终止字符(字符串下标超出范围)

C memset - 优雅地添加一个空终止符