C 需要最后的'\0';在fgets中
我见过一些使用C 需要最后的'\0';在fgets中,c,string,format,fgets,C,String,Format,Fgets,我见过一些使用fgets(例如)的情况如下: char buff[7]=""; (……) 有趣的是,如果我提供像“aaaaaaaaaaaaa”这样的长输入,fgets将在这里将其截断为“aaaaaa”,因为第7个字符将用于存储'\0' 但是,在执行此操作时: int i=0; for (i=0;i<7;i++) { buff[i]='a'; } printf("%s\n",buff); 然后提供过长的输入,生成的buff字符串将自动包含两个'\0'字符,一个在数组中,一个在系统
fgets
(例如)的情况如下:
char buff[7]="";
(……)
有趣的是,如果我提供像“aaaaaaaaaaaaa”这样的长输入,fgets
将在这里将其截断为“aaaaaa”,因为第7个字符将用于存储'\0'
但是,在执行此操作时:
int i=0;
for (i=0;i<7;i++)
{
buff[i]='a';
}
printf("%s\n",buff);
然后提供过长的输入,生成的buff
字符串将自动包含两个'\0'
字符,一个在数组中,一个在系统写入的字符串之后
我还注意到,这样做
fgets(buff,(sizeof(buff)+17),stdin);
将仍然工作,并输出非常长的字符串,而不会崩溃。据我猜测,这是因为fgets
将一直写入,直到sizeof(buff)+17
,最后要写入的字符将恰好是'\0'
,确保任何即将到来的字符串读取过程都将正确终止(尽管内存仍然混乱)
那么,fgets(buff,(sizeof(buff)+1),stdin)呢代码>?这将耗尽在buff
中正确分配的所有空间,然后在其后面写一个'\0'
,从而覆盖系统以前写的'\0'
。换句话说,是的,fgets
将超出范围,但可以证明,当只向写入长度添加一个时,程序将永远不会崩溃
最后,问题来了:fgets
为什么总是用一个'\0'
终止它的写入,而另一个'\0'
,由系统放在数组后面,已经存在?为什么不喜欢一个接一个的for
-基于循环的写操作,它可以访问整个数组并编写程序员想要的任何东西,而不会危及任何东西
非常感谢您的回答
编辑:事实上,没有证据可以证明,只要我不知道在分配buff[7]时神秘出现的第8个'\0'
是否是C标准的一部分,特别是对于字符串数组。如果没有,那么…这只是运气,它的工作:-)
但可以证明,当只增加一次写入长度时,程序永远不会崩溃
不!你不能证明这一点!不是在数学证明的意义上。您只展示了在您的系统上,使用您的编译器,使用您使用的特定编译器设置,使用特定的环境配置,它可能不会崩溃。这远远不是数学证明
事实上,C标准本身虽然保证您可以获得“数组最后一个元素后的一个位置”的地址,但它还声明,取消引用该地址(即尝试从该地址读取或写入)是未定义的行为
这意味着在这种情况下,一个实现可以做任何事情。它甚至可以用天真的推理做你期望的事情(即工作——但这纯粹是运气),但它也可能崩溃,或者它也可能格式化你的高清(如果你非常非常不走运的话)。在编写系统软件(例如,设备驱动程序或裸机上运行的程序)时尤其如此,即没有操作系统保护您免受编写错误代码的最恶劣后果
编辑这应回答评论中提出的问题(C99标准草案):
7.19.7.2 fgets功能
简介
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);
#包括
字符*fgets(字符*s,整数n,
文件*限制流);
说明
fgets函数读取的字符数最多比n指定的字符数少一个
从stream指向的流到s指向的数组。没有额外的
在新行字符(保留)后或在文件结尾后读取字符。A.
在最后一个字符读入数组后立即写入空字符
返回
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);
如果成功,fgets函数将返回s。如果遇到文件结尾并且没有
已将字符读入数组,数组的内容保持不变,并且
返回空指针。如果在操作过程中发生读取错误,则会删除数组内容
不确定,返回空指针
编辑:由于问题似乎在于对字符串是什么的误解,因此这是标准的相关摘录(我的重点):
7.1.1术语的定义
字符串是以第一个null结尾的连续字符序列
字符。术语多字节字符串有时被用来强调特殊字符
处理字符串中包含的多字节字符或避免混淆
用一根宽大的绳子。指向字符串的指针是指向其首字母(最低地址)的指针
性格字符串的长度是空字符前面的字节数和
字符串的值是所包含字符的值的顺序
但可以证明,当只增加一次写入长度时,程序永远不会崩溃
不!你不能证明这一点!不是在数学证明的意义上。您只展示了在您的系统上,使用您的编译器,使用您使用的特定编译器设置,使用特定的环境配置,它可能不会崩溃。这远远不是数学证明
事实上,C标准本身虽然保证您可以获得“数组最后一个元素后的一个位置”的地址,但它还声明,取消引用该地址(即尝试从该地址读取或写入)是未定义的行为
这意味着在这种情况下,一个实现可以做任何事情。它甚至可以通过天真的推理(即
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);