Confusion about file I/O (C) - c

fwrite(&studentg,sizeof(studentg),1,p);
while(!feof(p))
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
Why I put only one object in file,but it output two same line?
And if I put two objects in file,it output one object correct,but another repeated.
I try show feof(p)'s return value,it show me that after fread ,feof(p)'s return value is still 0.Can anyone explain how it happens?

You won't get an end of file until you try to read beyond the file. This means that you have to check eof before the print:
fwrite(&studentg,sizeof(studentg),1,p);
finish = 0;
while(!finish)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
finish = feof(p);
if (!finish)
{
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
}
or
fwrite(&studentg,sizeof(studentg),1,p);
while(1)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
if (feof(p)) break;
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}

From http://www.cplusplus.com/reference/cstdio/feof/:
"This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file."
This means that end of file is usually detected after an operation.
To fix your code, you may for example replace the condition in while loop with 1 or true and break execution when eof is reached (run feof inside loop).

Use of feof is one of the biggest misconception among beginners in File I/O. Everybody at some point has done the same mistake once or twice.
The way you have used it is Pascal's way but C way is different. The difference is::
Pascal's function returns true if the next read will fail because of end of file.
C's function returns true if the last function failed.
Thats why your code prints the last line twice because after the last line is read in and printed out, feof() will still return 0 (false) and the loop will continue. The next fgets() fails and so the line variable holding the contents of the last line is not changed and is printed out again. After this, feof() will return true (since fgets() failed) and the loop ends.
The correct way to use it is::
while( 1 ) {
fgets(line, sizeof(line), fp);
if ( feof(fp) ) /* check for EOF right after fgets() */
break;
fputs(line, stdout);
}
Still better way::
while( fgets(line, sizeof(line), fp) != NULL )
fputs(line, stdout);

First of all you should include a complete, reproducing, example to what you want to do, not a combined fragment of the code, which is hard to reproduce. Otherwise, note that using fwrite()/fread() on struct contents directly is not portable (see the free online book Porting UNIX Software), and is prone to errors. But you didn't provide enough context for us to understand what went wrong.

Related

fscanf is scanning an extra character at the end

it is always printing an extra character at the end. here is the code:
#include <stdio.h>
int main ()
{
char bit;
FILE *fp_read,*fp_write;
fp_read = fopen("test.txt","r");
if(fp_read==NULL) {
printf("Error!! Unable to open the file!!");
return 1;
}
while(!feof(fp_read)) {
fscanf(fp_read,"%c",&bit);
printf("%c",bit);
}
fclose(fp_read);
return 0;
}
if test.txt contains 010101 it prints 0101011 . if 00110 it prints 001100. if it contains abc it prints abcc . that means it always repeats the last character.
What is the problem ? can anybody explain ?
I am not able to reproduce the error.
Refer to David Bowling's first comment in the original post for a neat explanation.
The cppreference page for feof has a shorter version.
The eof function only reports the stream state as reported by the most recent I/O operation, it does not examine the associated data source. For example, if the most recent I/O was a fgetc, which returned the last byte of a file, feof returns zero. The next fgetc fails and changes the stream state to end-of-file. Only then feof returns non-zero.
In typical usage, input stream processing stops on any error; feof and ferror are then used to distinguish between different error conditions.
This means that the use of feof in the while loop may not be appropriate. The last character from the file may be junk and will be different in different systems.
Try doing this instead.
while(fscanf(fp_read,"%c",&bit) != EOF) {
printf("%c",bit);
}

need of fseek() in c

Part of Code 1:-
while(1)
{
ch=fgetc(pt);
if(c==EOF)
{
break;
}
if(c==' ')
{
fputc('z',pt);
}
}
Part of Code 2:-
while(1)
{
ch=fgetc(pt);
if(c==EOF)
{
break;
}
if(c==' ')
{
fseek(pt,0,SEEK_CUR);
fputc('z',pt);
fseek(pt,0,SEEK_CUR);
}
}
I want to replace next character after every space in a file. That file is pointed by the pointer pt.
Both the code shows no error and runs fine, but when I externally opens the .txt file, first code did nothing whereas the second code replaces the next character after space successfully.
Clearly fseek(pt,0,SEEK_CUR); is making the difference.
So I am unable to understand that what it is doing in the second code?
The use of fseek() here - The C standard requires a positioning operation between a read and a write operation on an update stream, or between a write and a read. This is a positioning operation between a write and a read. It is not a no-op; it places the stream into a mode which allows the next fgetc() to work correctly, reliably, across platforms, as required by the C standard.
EDIT:
2 fseek() calls are required because the first one acts as the "no-op" call between an fgetc() and a subsequent fputc() call. After the fputc(), the second one acts as the "no-op" between the fputc() and the subsequent fgetc() call. (since a loop is running)

segmentation fault in file handling

int main()
{
FILE *f;
f=fopen("words.txt","r");
char wd[10];
string word;
printf("Enter a word to be searched\n");
word=GetString();
while (!feof(f))
{
fscanf(f,"%s",wd);
//printf("%s\n",wd);
if(strcmp(word,wd)==0)
{
printf("Yes\n");
break;
}
}
fclose(f);
return 0;
}
If the word to be searched, is present in the file, it is giving the correct answer- YES, otherwise, its giving segmentation fault(core dumped).
Please help!!
Line 6: string word;
There is no string data type in C. And,
Line 8: word = GetString();
You didn't include definition of function. Assuming it returns pointer to a string, but won't work anyway because line 6 will not compile.
Use: char word[10] if your sure word won't be longer than 9 characters.
#gnometorule was correct. You're reading one more time than you need to. If you checked your return value, you would find fscanf probably returned EOF. What you want to do is read the file as long as fscanf returns an expected value. Since you are reading 1 item, it should return 1. If it doesn't, there is a problem. Moreover, feof will only be true if the end of the file was reached. What if there was a read error? You may be trying to read from a file that has its error indicator set, and feof won't detect that.
Review the following code. It should give you an idea of how to handle files.
/* This is used to determine whether an end-of-file error message should be printed or the word was found. */
int cmp_result;
/* Stop reading when the file can't be read or the words are equal. */
do
cmp_result = strcmp(word, wd);
while (fscanf(f, "%s", wd) == 1 && cmp_result != 0);
/* Check for a file read error. */
if (ferror(f))
printf("Error reading file\n");
/* End of file reached before words are equal; feof(f) may be true when cmp_result==0 or not, so checking cmp_result is more reliable in this case. */
else if (cmp_result != 0)
printf("Word '%s' not found\n", word);
/* Words are equal. */
else
printf("Yes\n");
The logic is that if the loop was exited, there was a read error or the word was found. The branching statements after the loop test this.
First, the file's error indicator is checked. If it isn't set, the end of the file was reached, or the word was found.
If the word was found, the end of file indicator may be set or not. But if the word wasn't found, the end of file indicator must be set, else the loop wouldn't have exited since we already ruled out the error indicator in the first if statement. This is why we check the comparison result instead of using feof(f).
If those cases fail, we are left with one possibility: the word was found.
I hope this helps!
Anytime while (!feof(f)) is in your code, it almost means that you are in the wrong place. feof() will only be set after reading the end of the stream. It does not indicate, that the next read will be the end of the stream. See here for more info.
Replace
while (!feof(f))
{
fscanf(f,"%s",wd);
... ...
}
by
while (fscanf(f,"%s",wd))
{
... ...
}

EOF reading last line twice

I am pretty new to C and have a very simple function for displaying file contents here. It works fine, except the last line of my file prints twice...I know that it has to do w/EOF but I can't figure out how to get the function to recognize EOF as the last line and not run once more. I know there are a billion places on the internet with similar issues, but lots were for C++ and since I am new I thought it would be best to just use my own code. Here is the code:
{
int count=0, fileEnd=0;
FILE* rockPtr=fopen("rockact.txt", "r");
printf("\n%8s%8s%8s%8s%8s\n", "BANDID", "NAME", "SIZE", "CREW", "TRANS");
do
{
fileEnd=fscanf(rockPtr, "%d%s%d%d%s", &(tempBand.rockid), tempBand.bandname, &(tempBand.bandsize), &(tempBand.crewsize), tempBand.transport);
if (fileEnd !=EOF); //checks EOF has not been reached
{
printf("\n%8d%8s%8d%8d%8s", tempBand.rockid, tempBand.bandname, tempBand.bandsize, tempBand.crewsize, tempBand.transport);
count++;
}
}
while (fileEnd !=EOF);
fclose(rockPtr);
printf("\n The total amount of rock acts on file is %d\n", count);
}
Your if condition doesn't want the semi-colon:
if (fileEnd !=EOF); // This semicolon is wrong!
The semicolon is a null statement and is the body of the if.
I'd rather see the whole loop cast as a while loop:
while (fscanf(rockPtr, "%d%s%d%d%s", &tempBand.rockid, tempBand.bandname,
&tempBand.bandsize, &tempBand.crewsize, tempBand.transport)) == 5)
{
printf("\n%8d%8s%8d%8d%8s", tempBand.rockid, tempBand.bandname,
tempBand.bandsize, tempBand.crewsize, tempBand.transport);
count++;
}
If you want to worry about it, you can spot the difference between EOF, read error and format error after the loop. Note that the check is that all values were converted OK.
you have ; after if - remove it
also, check manual for fscanf
If a reading error happens or the end-of-file is reached while
reading, the proper indicator is set (feof or ferror). And, if either
happens before any data could be successfully read, EOF is returned.
This mean that you can read at least partial data from file, reach EOF or error, but fscanf will not return it.
You should use feof function to check whether end of file is reached
so your logic should be:
read from file
if anything is read - display it, here I mean you should compare returned number with count of arguments, not with EOF
check for feof
UPDATE: during opening/reading from file you should always check ferror, as EOF is not the only problem

Why the fscanf is used 2 times with: while( !feof(File))

why when using fscanf to acquire data from a file, is used 2 times, once before the "!feof(fin)" and later, as shown in the code below:
fscanf(fin, "%s", letta);
while(!feof(fin)){
fscanf(fin, "%s", letta);
}
the word read is not the same?
No the word read would not be the same since you read from the file twice, you would get different data each time.
The condition in the while tests to see if you are at the end of file, in order to do that a read attempt must have been made, which requires the fscanf() before the loop.
Once you are inside the loop you want to continue reading from the file. Presumably there would be more code inside the loop to process the data you are reading.
In the code you have posted, if you encountered the end of file with your first read attempt, you wouldn't enter the (while) loop.
Contrast this with a do-while construct where the test is at the bottom of the loop (ie the read occurs only once, at the "bottom" of the loop). There you will always enter the loop at least once.
There's probably no point in using feof() like this here, yet many people who are (I guess, apologies if I'm mistaken) learning C seem to "want to".
The fact is that fscanf() itself has a return value; if the file ends it will fail to do the requested scanning, and it will tell you so. It will even return the special constant EOF if the file ends. So just loop on the return value of fscanf():
while( fscanf(fin, "%s", letta) == 1 )
{
/* Process, parse, store or do whatever with letta. */
}
Because the EOF flag is only set after a call to fscanf. The condition while(!feof(fin)) doesn't make sense when fscanf hasn't been called yet.
feof doesn't return true until after you try to read past the end of file. Imagine a file like the following:
This is a test$
^
where ^ indicates the current location in the file and $ represents EOF. After the first call to fscanf(fin, "%s", letta);, the stream looks like this:
This is a test$
^
After three iterations of the loop (reading "is", "a", and "test"), you have this:
This is a test$
^
At this point, feof(fin) still returns false, because at this point all you know is that you've reached the end of the string "test". So your loop will execute one more time. Since you're at the end of the file, there's nothing to read, so the contents of letta will not be changed, so it will look like you've read "test" twice. Now feof(fin) will return true.
The moral of the story is that you should not use feof as your loop condition; rather, you should use the result of the read operation itself, like so:
errno = 0;
while (fscanf(fin, "%s", letta) == 1)
{
// process letta
}
if (feof(fin))
{
printf("Reached end of file\n");
}
else
{
perror("Error on read");
}

Resources