我已经看到了几个这样的用法fgets
(例如,here):
char buff[7]="";
(...)
fgets(buff, sizeof(buff), stdin);
有趣的是,如果我提供像“aaaaaaaaaaa”这样的长输入,fgets
将在此处将其截断为“aaaaaa”,因为第 7 个字符将用于存储'\0'
.
但是,这样做时:
int i=0;
for (i=0;i<7;i++)
{
buff[i]='a';
}
printf("%s\n",buff);
我总是会得到 7'a'
秒,程序不会崩溃。但是如果我尝试写 8 'a'
s,它会的。
正如我后来看到的那样,这样做的原因是,至少在我的系统上,当我分配char buff[7]
(有或没有=""
)时,第 8 个字节(从 1 开始计数,而不是从 0 开始计数)被设置为 0。据我猜测,事情就是这样完成的,这样一个for
有 7 次写入的循环,然后是一个格式化为读取的字符串,无论最后一个要写入的字符是否是,都可以成功,'\0'
从而避免程序员设置最后一个 '\0 ' 他自己,在单独编写字符时。
由此可知,在
fgets(buff, sizeof(buff), stdin);
然后提供太长的输入,生成的buff
字符串将自动包含两个'\0'
字符,一个在数组内,一个在它之后由系统写入。
我还观察到这样做
fgets(buff,(sizeof(buff)+17),stdin);
仍然可以工作,并输出一个很长的字符串,而不会崩溃。根据我的猜测,这是因为fgets
将一直写入直到sizeof(buff)+17
,并且要写入的最后一个字符将恰好是 a '\0'
,从而确保任何即将进行的字符串读取过程都将正确终止(尽管无论如何内存都被弄乱了)。
但是,那又如何fgets(buff, (sizeof(buff)+1),stdin);
呢?这将用完所有在 中正确分配的空间,buff
然后'\0'
在它之后写一个,从而覆盖......'\0'
先前由系统写入的空间。换句话说,是的,fgets
会越界,但可以证明,当写长度只加一个时,程序永远不会崩溃。
所以最后,问题来了:为什么fgets
总是用 a 终止它的写入'\0'
,而另一个'\0'
由系统放置在数组之后的已经存在?为什么不喜欢逐个for
循环的写入,它可以访问整个数组并编写程序员想要的任何东西,而不会危及任何东西?
非常感谢您的回答!
编辑:确实,没有证据可能,只要我不知道'\0'
在分配 buff[7] 时神秘出现的第 8 个是否是 C 标准的一部分,特别是对于字符串数组。如果没有,那么......它只是运气好:-)