简体   繁体   English

Visual Studio Code 如何处理“r+”模式下文件 I/O 的 fputs 语句?

[英]How does Visual Studio Code handle the fputs statement for File I/O in "r+" mode?

I have written a code我写了一段代码

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

I have tried to insert a string inside an already existing file "lets.txt"我试图在一个已经存在的文件“lets.txt”中插入一个字符串原始文本文件

but when I run this code, this is shown in the Terminal但是当我运行这段代码时,它显示在终端中运行代码的终端照片

I was expecting this to just put Jenny into the final file but it's also adding other text which was present before it and lots of NULL. Is this because of something like temporary memory storage or something like that or just some mistake in the code?我原以为这只是将 Jenny 放入最终文件,但它也添加了之前存在的其他文本和大量 NULL。这是因为临时 memory 存储或类似的东西还是代码中的一些错误? [![不知道](https://i.stack.imgur.com/GQmpK.png)](https://i.stack.imgur.com/GQmpK.png)

Re: "I changed the condition for the while loop to this simple form- ch = fgetc(fp); while(ch.= EOF) But it is still showing the same result.回复:“我将 while 循环的条件更改为这个简单的形式 - ch = fgetc(fp); while(ch.= EOF) 但它仍然显示相同的结果。


The value returned by getchar() must be stored in an int : getchar()返回的值必须存储在int中:

ch= fgetc(fp);

ch has been declared as a char . ch已声明为char Storing the value in a char makes testing for EOF unreliable.将值存储在char中会使EOF测试变得不可靠。 C17 states that EOF has a negative int value. C17 声明EOF具有负 int 值。 On some implementations, char is unsigned , hence it can't represent negative values.在某些实现中, charunsigned ,因此它不能表示负值。

On implementations where the type char is signed, assuming EOF is defined as -1 (which is the case on most implementations), it's impossible to distinguish EOF from the character code 255 (which would be stored as the value -1 in a char , but as 255 in an int ).在对类型char进行签名的实现中,假设EOF定义为-1 (大多数实现都是这种情况),不可能将EOF与字符代码255 (将作为值-1存储在char中,但在int中为255 )。

From the man page:从手册页:

fgetc(), getc(), and getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error. fgetc()、getc() 和 getchar() 在文件末尾或错误时将读取的字符返回为 unsigned char 转换为int或 EOF。

It further states:它进一步指出:

If the integer value returned by getchar() is stored into a variable of type char and then compared against the integer constant EOF, the comparison may never succeed, because sign- extension of a variable of type char on widening to integer is implementation-defined.如果将 getchar() 返回的 integer 值存储到 char 类型的变量中,然后与 integer 常量 EOF 进行比较,比较可能永远不会成功,因为 char 类型变量的符号扩展扩展到 integer 是实现定义的.

which is relevant to fgetc as well.这也与fgetc相关。


Possible fix:可能的修复:

Declare ch as an int .ch声明为int

First of all, the lines首先,线条

char ch,ch1;
while(!feof(fp))
{
    ch= fgetc(fp);
    printf("%c",ch);
}

are wrong.错了。

If you want ch to be guaranteed to be able to represent the value EOF and also want to be able to distinguish it from every possible character code, then you must store the return value of fgetc in an int , not a char .如果您希望ch保证能够表示值EOF并且还希望能够将它与每个可能的字符代码区分开来,那么您必须将fgetc的返回值存储在int中,而不是char中。 Please note that fgetc returns an int , not a char .请注意fgetc返回一个int ,而不是一个char See this other answer for more information on this issue.有关此问题的更多信息,请参阅此其他答案

Also, the function feof will only return a non-zero value (ie true) if a previous read operation has already failed due to end-of-file.此外,function feof仅在先前的读取操作因文件结束而失败时才返回非零值(即 true)。 It does not provide any indication of whether the next read operation will fail.它不提供下一次读取操作是否失败的任何指示。 This means that if fgetc returns EOF , you will print that value as if fgetc were successful, which is wrong.这意味着如果fgetc返回EOF ,您将打印该值,就好像fgetc成功一样,这是错误的。 See the following question for further information on this issue:有关此问题的更多信息,请参阅以下问题:

Why is “while(?feof(file) )” always wrong?为什么“while(?feof(file) )”总是错误的?

For the reasons stated above, I suggest that you change these lines to the following:由于上述原因,我建议您将这些行更改为以下内容:

int ch, ch1;

while ( ( ch = fgetc(fp) ) != EOF )
{
    printf( "%c", ch );
}

Another issue is that when a file is opened in update mode (ie it is opened with a + in the mode string, for example "r+" as you are doing), you cannot freely change between reading and writing.另一个问题是,当文件以更新模式打开时(即在模式字符串中使用+打开,例如您正在执行的"r+" ),您无法在读写之间自由切换。 According to §7.21.5.3 ¶7 of the ISO C11 standard ,根据ISO C11 标准的§7.21.5.3¶7

  • output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function ( fseek , fsetpos , or rewind ), and在没有对fflush function 或文件定位 function( fseekfsetposrewind )的干预调用的情况下,不应直接在 output 之后输入,并且

  • input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.在没有对文件定位 function 的中间调用的情况下,输入不得直接跟在 output 之后,除非输入操作遇到文件结尾。

If you break any of these rules, than your program will be invoking undefined behavior , which means that anything can happen, which includes the possibility that you get invalid output.如果您违反任何这些规则,那么您的程序将调用未定义的行为,这意味着任何事情都可能发生,其中包括您获得无效 output 的可能性。

For this reason, I suggest that you change the lines因此,我建议您更改行

fputs("Jenny",fp);
ch1 = fgetc(fp);

to:到:

fseek( fp, 0, SEEK_CUR );
fputs("Jenny",fp);
fflush( fp );
ch1 = fgetc(fp);

In contrast to the line fflush( fp );对比行fflush( fp ); , which is absolutely necessary, the line fseek( fp, 0, SEEK_CUR ); ,这是绝对必要的,行fseek( fp, 0, SEEK_CUR ); actually isn't necessary according to the rules stated above, because you encountered end-of-file.根据上述规则实际上没有必要,因为您遇到了文件结尾。 But it probably is a good idea to keep that line anyway, for example in case you later change your program to stop reading for some other reason besides end-of-file.但无论如何保留该行可能是个好主意,例如,以防万一您以后更改程序以出于文件结束之外的其他原因停止读取。 In that case, that line would be required.在这种情况下,将需要该行。

You haven't set the file pointer when switching between read and write.在读写之间切换时,您还没有设置文件指针。 The MSVC man page says about fopen MSVC 手册页介绍了fopen

However, when you switch from reading to writing, the input operation must encounter an EOF marker.但是,当你从读切换到写时,输入操作一定会遇到EOF标记。 If there's no EOF , you must use an intervening call to a file positioning function. The file positioning functions are fsetpos , fseek , and rewind .如果没有EOF ,则必须使用对文件定位 function 的干预调用。文件定位函数是fsetposfseekrewind When you switch from writing to reading, you must use an intervening call to either fflush or to a file positioning function.当您从写入切换到读取时,您必须使用对fflush或文件定位 function 的干预调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM