只是想知道为什么会这样。我渴望了解更多关于低级语言的知识,而且我只了解 C 的基础知识,这已经让我感到困惑。
像 PHP 这样的语言会在解释和/或解析字符串时自动终止字符串吗?
只是想知道为什么会这样。我渴望了解更多关于低级语言的知识,而且我只了解 C 的基础知识,这已经让我感到困惑。
像 PHP 这样的语言会在解释和/或解析字符串时自动终止字符串吗?
记住字符串在 C 中的工作方式:它们由一堆字节组成,后跟一个空字符,其值为 0。这有两个明显的含义:
没有办法知道字符串在哪里结束(即字符串长度)而不通过它,寻找末尾的空字符。您的字符串中不能有任何零。因此,您不能在 C 字符串中存储任意二进制 blob,例如 JPEG 图片。 为什么 C 字符串会这样工作?这是因为发明了 UNIX 和 C 编程语言的 PDP-7 微处理器具有 ASCIZ 字符串类型。ASCIZ 的意思是“以 Z(零)结尾的 ASCII”。
这是存储字符串的唯一方法吗?不,事实上,这是存储字符串的最糟糕的方式之一。对于非平凡的程序、API、操作系统、类库,你应该避免像瘟疫一样的 ASCIZ 字符串。
C 字符串是字符数组,而 C 数组只是指向内存位置的指针,内存位置是数组的起始位置。但数组的长度(或结尾)也必须以某种方式表示;如果是字符串,则使用空终止。另一种选择是以某种方式将字符串的长度与内存指针一起携带,或者将长度放在第一个数组位置,或其他任何地方。这只是一个约定俗成的问题。
像 Java 或 PHP 这样的高级语言会自动透明地将大小信息与数组一起存储,因此用户无需担心它们。
想想什么是内存:一个连续的字节大小的单元块,可以用任何位模式填充。
2a c6 90 f6
字符只是这些位模式之一。它作为字符串的含义取决于您如何对待它。如果您查看内存的同一部分,但使用整数视图(或其他类型),您会得到不同的值。
如果您有一个变量,它是指向内存中一堆字符的开头的指针,您必须知道该字符串何时结束以及下一段数据(或垃圾)何时开始。
让我们看看内存中的这个字符串......
H e l l o , w o r l d ! \0
^
|
+------ Pointer to string
...我们可以看到字符串在!
字符之后逻辑上结束。如果没有\0
(或任何其他方法来确定它的结束),当我们在内存中寻找我们已经用那个字符串完成时,我们怎么知道?其他语言使用字符串类型携带字符串长度来解决这个问题。
当我对计算机的基础知识有限时,我问了这个问题,而这个答案在很多年前会有所帮助。我希望它也对其他人有所帮助。:)
C 本身没有字符串的概念。字符串只是字符数组(或 unicode 等的 wchars)。
由于这些事实,C 无法检查字符串的长度,因为没有“mystring->length”,因此在某处没有设置长度值。找到字符串结尾的唯一方法是遍历它并检查 \0。
C 有一些字符串库,它们使用类似的结构
struct string {
int length;
char *data;
};
消除对 \0 终止的需要,但这不是标准 C.
C++、PHP、Perl 等语言都有自己的内部字符串库,这些库通常有一个单独的长度字段,可以加速某些字符串函数并消除对 \0 的需求。
其他一些语言(如 Pascal)使用称为(令人惊讶的)Pascal String 的字符串类型,它将长度存储在字符串的第一个字节中,这就是这些字符串长度限制为 255 个字符的原因。
因为在 C 中,字符串只是通过指向第一个字符的指针访问的字符序列。
指针中没有空间来存储长度,因此您需要一些指示字符串末尾的位置。
在 C 中,决定这将由一个空字符表示。
例如,在 pascal 中,字符串的长度记录在指针之前的字节中,因此 pascal 字符串的最大长度为 255 个字符。
这是一种约定——人们可以用另一种算法来实现它(例如缓冲区开头的长度)。
在诸如汇编程序之类的“低级”语言中,很容易有效地测试“NULL”:与跟踪长度计数器相比,这可能有助于决定使用 NULL 终止的字符串。
它们需要以空值终止,以便您知道它们有多长。是的,它们只是字符数组。
像 PHP 这样的高级语言可能会选择对您隐藏空终止符或根本不使用它 - 例如,它们可能会保持一个长度。由于涉及的开销,C 不会那样做。高级语言也可能不会将字符串实现为 char 数组 - 例如,它们可以(并且有些确实)将它们实现为 char 数组列表。
在 C 中,字符串由分配在连续内存块中的字符数组表示,因此必须有一个指示块结束的指示符(即空字符),或者存储长度的方式(如 Pascal 字符串以长度为前缀)。
在 PHP、Perl、C# 等语言中,字符串可能具有也可能没有复杂的数据结构,因此您不能假设它们具有空字符。作为一个人为的示例,您可以使用一种表示字符串的语言,如下所示:
class string
{
int length;
char[] data;
}
但是您只会将其视为没有长度字段的常规字符串,因为这可以通过语言的运行时环境计算出来,并且仅在其内部用于正确分配和访问内存。
它们是空终止的,因为大量标准库函数都希望它们是空终止的。