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("nnYou want to write something? (1/0)");
int n;
scanf("%d",&n);
if(n==1)
{
fputs("Jenny",fp);
ch1 = fgetc(fp);
printf("%cn", 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?
3
Answers
The value returned by
getchar()
must be stored in anint
:ch
has been declared as achar
. Storing the value in achar
makes testing forEOF
unreliable. C17 states thatEOF
has a negative int value. On some implementations,char
isunsigned
, hence it can’t represent negative values.On implementations where the type
char
is signed, assumingEOF
is defined as-1
(which is the case on most implementations), it’s impossible to distinguishEOF
from the character code255
(which would be stored as the value-1
in achar
, but as255
in anint
).From the man page:
It further states:
which is relevant to
fgetc
as well.Possible fix:
Declare
ch
as anint
.You haven’t set the file pointer when switching between read and write. The MSVC man page says about
fopen
First of all, the lines
are wrong.
If you want
ch
to be guaranteed to be able to represent the valueEOF
and also want to be able to distinguish it from every possible character code, then you must store the return value offgetc
in anint
, not achar
. Please note thatfgetc
returns anint
, not achar
. 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 iffgetc
returnsEOF
, you will print that value as iffgetc
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:
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
to:
In contrast to the line
fflush( fp );
, which is absolutely necessary, the linefseek( 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.