Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 需要最后的'\0';在fgets中_C_String_Format_Fgets - Fatal编程技术网

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);