[英]How does Visual Studio Code handle the fputs statement for File I/O in "r+" mode?
我写了一段代码
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
fp=fopen("lets.txt","r+");
if(fp==NULL)
{
printf("ERROR");
exit(1);
}
else
{
char ch,ch1;
while(!feof(fp))
{
ch= fgetc(fp);
printf("%c",ch);
}
printf("\n\nYou want to write something? (1/0)");
int n;
scanf("%d",&n);
if(n==1)
{
fputs("Jenny",fp);
ch1 = fgetc(fp);
printf("%c\n", ch1);
while(ch1 != EOF)
{
ch1=fgetc(fp);
printf("%c",ch1);
}
fclose(fp);
}
else{
printf("File Closed ");
fclose(fp);
}
}
}
我试图在一个已经存在的文件“lets.txt”中插入一个字符串
我原以为这只是将 Jenny 放入最终文件,但它也添加了之前存在的其他文本和大量 NULL。这是因为临时 memory 存储或类似的东西还是代码中的一些错误?
回复:“我将 while 循环的条件更改为这个简单的形式 - ch = fgetc(fp); while(ch.= EOF) 但它仍然显示相同的结果。
getchar()
返回的值必须存储在int
中:
ch= fgetc(fp);
ch
已声明为char
。 将值存储在char
中会使EOF
测试变得不可靠。 C17 声明EOF
具有负 int 值。 在某些实现中, char
是unsigned
,因此它不能表示负值。
在对类型char
进行签名的实现中,假设EOF
定义为-1
(大多数实现都是这种情况),不可能将EOF
与字符代码255
(将作为值-1
存储在char
中,但在int
中为255
)。
从手册页:
fgetc()、getc() 和 getchar() 在文件末尾或错误时将读取的字符返回为 unsigned char 转换为int或 EOF。
它进一步指出:
如果将 getchar() 返回的 integer 值存储到 char 类型的变量中,然后与 integer 常量 EOF 进行比较,比较可能永远不会成功,因为 char 类型变量的符号扩展扩展到 integer 是实现定义的.
这也与fgetc
相关。
可能的修复:
将ch
声明为int
。
首先,线条
char ch,ch1;
while(!feof(fp))
{
ch= fgetc(fp);
printf("%c",ch);
}
错了。
如果您希望ch
保证能够表示值EOF
并且还希望能够将它与每个可能的字符代码区分开来,那么您必须将fgetc
的返回值存储在int
中,而不是char
中。 请注意fgetc
返回一个int
,而不是一个char
。 有关此问题的更多信息,请参阅此其他答案。
此外,function feof
仅在先前的读取操作已因文件结束而失败时才返回非零值(即 true)。 它不提供下一次读取操作是否会失败的任何指示。 这意味着如果fgetc
返回EOF
,您将打印该值,就好像fgetc
成功一样,这是错误的。 有关此问题的更多信息,请参阅以下问题:
为什么“while(?feof(file) )”总是错误的?
由于上述原因,我建议您将这些行更改为以下内容:
int ch, ch1;
while ( ( ch = fgetc(fp) ) != EOF )
{
printf( "%c", ch );
}
另一个问题是,当文件以更新模式打开时(即在模式字符串中使用+
打开,例如您正在执行的"r+"
),您无法在读写之间自由切换。 根据ISO C11 标准的§7.21.5.3¶7 ,
在没有对fflush
function 或文件定位 function( fseek
、 fsetpos
或rewind
)的干预调用的情况下,不应直接在 output 之后输入,并且
在没有对文件定位 function 的中间调用的情况下,输入不得直接跟在 output 之后,除非输入操作遇到文件结尾。
如果您违反任何这些规则,那么您的程序将调用未定义的行为,这意味着任何事情都可能发生,其中包括您获得无效 output 的可能性。
因此,我建议您更改行
fputs("Jenny",fp);
ch1 = fgetc(fp);
到:
fseek( fp, 0, SEEK_CUR );
fputs("Jenny",fp);
fflush( fp );
ch1 = fgetc(fp);
对比行fflush( fp );
,这是绝对必要的,行fseek( fp, 0, SEEK_CUR );
根据上述规则实际上没有必要,因为您遇到了文件结尾。 但无论如何保留该行可能是个好主意,例如,以防万一您以后更改程序以出于文件结束之外的其他原因停止读取。 在这种情况下,将需要该行。
在读写之间切换时,您还没有设置文件指针。 MSVC 手册页介绍了fopen
但是,当你从读切换到写时,输入操作一定会遇到
EOF
标记。 如果没有EOF
,则必须使用对文件定位 function 的干预调用。文件定位函数是fsetpos
、fseek
和rewind
。 当您从写入切换到读取时,您必须使用对fflush
或文件定位 function 的干预调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.