Home > Enterprise >  How does Visual Studio Code handle the fputs statement for File I/O in "r " mode?
How does Visual Studio Code handle the fputs statement for File I/O in "r " mode?

Time:01-23

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" The original text file

but when I run this code, this is shown in the Terminal Photo of Terminal on running the code

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? [![no idea](https://i.stack.imgur.com/GQmpK.png)](https://i.stack.imgur.com/GQmpK.png)

CodePudding user response:

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. Please note that fgetc returns an int, not a char. See this other answer for more information on this issue.

Also, the function feof will only return a non-zero value (i.e. true) if a previous read operation has already failed due to end-of-file. 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. See the following question for further information on this issue:

Why is “while( !feof(file) )” always wrong?

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 (i.e. it is opened with a in the mode string, for example "r " as you are doing), you cannot freely change between reading and writing. According to §7.21.5.3 ¶7 of the ISO C11 standard,

  • 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

  • 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.

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.

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

The line 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.

CodePudding user response:

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.


The value returned by getchar() must be stored in an int:

ch= fgetc(fp);

ch has been declared as a char. Storing the value in a char makes testing for EOF unreliable. C17 states that EOF has a negative int value. On some implementations, char is unsigned, hence it can't represent negative values.

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

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.

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.

which is relevant to fgetc as well.


Possible fix:

Declare ch as an int.

CodePudding user response:

You haven't set the file pointer when switching between read and write. The MSVC man page says about fopen

However, when you switch from reading to writing, the input operation must encounter an EOF marker. 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. When you switch from writing to reading, you must use an intervening call to either fflush or to a file positioning function.

  • Related