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"
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?
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
, orrewind
), andinput 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 noEOF
, you must use an intervening call to a file positioning function. The file positioning functions arefsetpos
,fseek
, andrewind
. When you switch from writing to reading, you must use an intervening call to eitherfflush
or to a file positioning function.