为啥我们需要在 C 中的字符数组末尾添加一个'\0'(null)?
Posted
技术标签:
【中文标题】为啥我们需要在 C 中的字符数组末尾添加一个\'\\0\'(null)?【英文标题】:Why do we need to add a '\0' (null) at the end of a character array in C?为什么我们需要在 C 中的字符数组末尾添加一个'\0'(null)? 【发布时间】:2012-12-03 22:59:28 【问题描述】:为什么我们需要在 C 中的字符数组末尾添加一个 '\0' (null)? 我在 K&R 2 (1.9 Character Array) 中读过它。书中查找最长字符串的代码如下:
#include <stdio.h>
#define MAXLINE 1000
int readline(char line[], int maxline);
void copy(char to[], char from[]);
main()
int len;
int max;
char line[MAXLINE];
char longest[MAXLINE];
max = 0;
while ((len = readline(line, MAXLINE)) > 0)
if (len > max)
max = len;
copy(longest, line);
if (max > 0)
printf("%s", longest);
return 0;
int readline(char s[],int lim)
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n')
s[i] = c;
++i;
s[i] = '\0'; //WHY DO WE DO THIS???
return i;
void copy(char to[], char from[])
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
我的问题是为什么我们将字符数组的最后一个元素设置为'\0'? 没有它,该程序可以正常工作... 请帮帮我...
【问题讨论】:
\0
表示字符串结束
局部变量没有在 C 中初始化。因此,局部变量 line
在你没有写入的地方有垃圾。如果垃圾恰好是0
,那么您的程序将在不显式写入空值的情况下运行。但是,如果您在line
变量中执行另一个readline
,并使该行比第一行短,您将在line
的第二行末尾看到第一行的剩余部分。在末尾写入空字符将防止这种情况发生。
【参考方案1】:
您需要以 '\0'
结束 C 字符串,因为这是库知道字符串在哪里结束的方式(在您的情况下,这是 copy()
函数所期望的)。
没有它,程序也能正常工作......
没有它,你的程序就有undefined behaviour。如果程序碰巧做了你期望它做的事情,你只是幸运(或者,更确切地说,不幸,因为在现实世界中,未定义的行为会选择在最不方便的情况下表现出来)。
【讨论】:
@SandyLee_user53167 这次你很幸运 :) @SandyLee_user53167 代码中的copy
函数一直运行,直到看到\0
字符。
不,绝对不是。你会导致不确定的行为。在这个简单的例子中它可能看起来有效,但这纯粹是运气。在不同的操作系统或编译器上,或者如果你正在做一些更复杂的事情,比如复制字符串,你会导致内存乱涂——覆盖它不应该写的部分内存。尝试在定义longest
(例如char x='Z';
)之前和之后添加诸如定义字符变量之类的内容,然后看看您的程序是否仍然符合您的预期..【参考方案2】:
在 c 中,“字符串”表示以空字符结尾的字符数组。将此与一个帕斯卡字符串进行比较,这意味着最多有 255 个字符,前面有一个表示字符串长度的字节(但不需要终止)。
每种方法都有其优点和缺点。
【讨论】:
注意事项:同时,流行的(嗯,或多或少)语言 Delphi 引入了各种类型的字符串,其中只有一种有 255 个字符的限制。所有其他(ansi、unicode、wide 等)都有(我认为)4 GB 的限制。 @alzaimar 嗯,这几天肯定比 per se pascal 更受欢迎。自己不知道。无论哪种方式,程序员都可以选择他或她的毒药,这总是很好。【参考方案3】:特别是指向未知长度的字符数组的字符串指针是NULL
终止符确定字符串长度的唯一方法。
link 上关于 NULL 终止的精彩讨论
【讨论】:
【参考方案4】:因为 C 将字符串定义为以第一个空字符终止并包括第一个空字符的连续字符序列。
基本上,C 的作者可以选择将字符串定义为字符序列 + 字符串的长度,或者使用魔术标记来分隔字符串的结尾。
有关该主题的更多信息,我建议阅读这篇文章:
Poul-Henning Kamp 的“最昂贵的单字节错误” http://queue.acm.org/detail.cfm?id=2010365
【讨论】:
【参考方案5】:您实际上已经在这里自己写了答案:
void copy(char to[], char from[])
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
此函数中的循环将继续进行,直到遇到数组 from 中的 '\0'。如果没有终止零,循环将继续执行未知数量的步骤,直到遇到零或无效的内存区域。
【讨论】:
【参考方案6】:真的,您确实不需要需要以 \0 结束字符数组。它是 char* 或需要由它结束的字符串的 C 表示形式。
对于数组,如果要将其传输到字符串(以char*表示),则必须在其末尾添加一个\0 。
另一方面,如果要将其寻址为 char* 并计划在其上使用 char* 函数,则需要在数组末尾添加 \0。
【讨论】:
【参考方案7】:数组中的'\0'
表示字符串的结尾,这意味着该字符之后的任何字符都不被视为字符串的一部分,并不意味着它们不是字符数组的一部分。也就是说,我们仍然可以通过索引来访问这些字符,但是当我们向这个字符数组调用与字符串相关的东西时,它们并不是一部分。
要使字符串具有正确的格式并能够与字符串函数一起正常工作,它必须是一个以空字符结尾的字符数组。如果没有 NULL,当我们在字符数组上调用字符串函数时,程序会显示未定义的行为。尽管大多数时候我们可能会对结果感到幸运,但这仍然是一种未定义的行为。
【讨论】:
【参考方案8】:它是字符串终止符号,当遇到这个时,编译器会知道你的字符串已经结束。
【讨论】:
编译器与此无关。它仅在运行时进行评估。以上是关于为啥我们需要在 C 中的字符数组末尾添加一个'\0'(null)?的主要内容,如果未能解决你的问题,请参考以下文章
何时/为啥需要 '\0' 来标记 (char) 数组的结尾?