My professor write a C code about fgets,feof with using stdin.
But I don't understand how it works.
fgets(list, 100, stdin);
while (!feof(stdin))
{
printf("feof!");
fgets(list, 100, stdin);
}
when i write a 'hello', function while is working.
why feof(stdin) returns 0?
I think first fgets read stdin buffer all of string(include '\0').
therefore I think while shouldn't work because feof(stdin) returns 1
What am i wrong?
Tip: always check the return value of input functions and most other I/O functions too.
fgets(list, 100, stdin); // Weak code
Yes, calling printf("feof!"); inside the loop is misleading as the end-of-file indicator for stdin is not set given the prior test condition while (!feof(stdin)).
How to read from stdin with fgets()?
Do not use feof() for this task for primary detection
fgets() returns NULL when:
An end-of-file just occurred in the previous input operation.
An end-of-file had occurred in the some input operations even before that.
An input error just occurred. Examples: file to read is an output stream or a parity error on some serial communication.
while (!feof(stdin)) only detects 1 & 2.
Unless the return value of fgets(list, 100, stdin) is checked, using list may be a problem.
feof() is useful after an I/O function returned the possibility of the need.
Size to the object, avoid magic numbers
Good usage:
char list[100];
while (fgets(list, sizeof list, stdin)) {
printf("%s", list):
}
if (feof(stdin)) {
puts("End-of-file");
} else if (ferror(stdin)) {
puts("Error");
} else {
puts("Unexpected state");
}
Related
I have a question about I/O in C language, how can I make a difference to know if the lecture of my file has ended or if the data can't be read (or has a problem) as in the both cases, fscanf returns EOF ?
Don´t rely only on the return value of fscanf(), rely beside this one on feof() and ferror() after the call to fscanf():
FILE* file;
if((file == fopen("file.txt","r")) == NULL)
{
fprintf(stderr, "File could not be opened!");
return EXIT_FAILURE;
}
char buf;
/******************************************************************************/
while(fscanf(file,"%c",buf) == 1) { // checks if an error was happen, else
// iterate to catching characters.
/* handling of read character */
}
if(ferror(file)) // checks if an I/O error occurred.
{
// I/O error handling
fprintf(stderr,"Input/Output error at reading file!");
clearerr(file);
// Further actions
}
else if(feof(file)) // checks if the end of the file is reached.
{
// end of file handling
fprintf(stderr,"Reached End of File!");
clearerr(file);
// Further actions
}
/******************************************************************************/
if(fclose(file) != 0)
{
fprintf(stderr, "File could not be closed properly!");
return EXIT_FAILURE;
}
As per fscanf() return value:
ISO/IEC 9899:2017
§ 7.21.6.2 - 16 - The fscanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
EOF is a macro with the value of -1, by itself it's not distinguishable as for the reasons why it occurs.
For this distinction § 7.21.6.2 - 19 recommends the use of feof() for end-of-file and ferror() for I/O error:
EXAMPLE 3 To accept repeatedly from stdin a quantity, a unit of measure, and an item name:
#include<stdio.h>
/*...*/
int count; floatquant;
charunits[21], item[21];
do {
count = fscanf(stdin, "%f%20sof%20s", &quant, units, item);
fscanf(stdin,"%*[^\n]");
} while(!feof(stdin) && !ferror(stdin));
My usual approach when reading formated input, is to check the inputed values. For a sample input of 2 integers you can do something like:
int a, b;
FILE* file;
//open file to read
while(fscanf(file, "%d %d", &a, &b) == 2){ //read each 2 integers in the file, stop when condition fails, i.e. there are nothing else to read or the read input is not an integer
//...handle inputs
}
This kind of read is safe and addresses all failure scenarios since it works for bad input and for "end of file".
I am trying to write user input to a txt file using a while loop.
But for some reason that I don't know, the while loop doesn't stop by clicking 'enter'.
when I click 'enter', I see "while loop executed" so I know the while loop iterated again even though I wanted to stop the while loop.
How to do it in a right way?
P.S: I use Microsoft Visual Studio recommended by my professor.
#include <stdio.h>
#include <string.h>
void main()
{
//writing to file
char write[100];
char fileName[100];
printf("give a name for file: ");
gets_s(fileName,99);
strcat(fileName,".txt");
FILE* pF = fopen(fileName, "w");
printf("what needs to be written?\n: ");
while(gets_s(write,99) != NULL)
{
printf("whileloop executed\n");
fprintf(pF,"%s\n", write);
}
fclose(pF);
}
Per Microsoft's gets_s() documentation, gets_s() returns NULL on end-of-file and error conditions:
Return Value
Returns buffer if successful. A NULL pointer indicates an error or
end-of-file condition. Use ferror or feof to determine which one
has occurred.
Hitting the enter key does not close the input stream and cause an end-of-file condition. It just places a zero-length line terminated with a newline in the input stream.
To do that on Windows from a terminal, one usually has to enter the CTRL-Z key combination.
You need to do some handling there as gets_s() will return and empty string when enter is hit. You can write an extra function to handle that:
size_t my_gets(char *buf,size_t len)
{
size_t ret=0;
if(gets_s(buf,len))
ret = strlen(buf);
return ret;
}
Then change your loop to:
while(my_gets(write,99))
{
...
P.S.- You should avoid calling variables with the same name of system functions (i.e. write).
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 9 years ago.
I'm a beginner of C. When I use this while loop to print the contains of a file. The last line will print twice on Linux. It should not get into while loop when reach the end of file. It has no problem on windows.
#include <stdio.h>
#include <unistd.h>
int main()
{
char string[400];
FILE *file_para;
// Open the file
if ((file_para = fopen("Test.txt", "r")) == NULL)
{
printf("cannot open file\n");
getchar();
return 0;
}
while (!feof(file_para))
{
fgets(string, 400, file_para);
printf("**** %s", string);
}
fclose(file_para);
getchar();
return 0;
}
This is the wrong way to use feof(). Use feof() to detect what went wrong after one of the main I/O functions failed. It does not predict whether you're about to reach EOF; it tells you when some I/O function has already reported EOF. C is not Pascal; in Pascal, you can (must?) check for EOF before calling the I/O functions.
while (fgets(string, sizeof(string), file_para) != 0)
{
...do printing, etc...
}
// If you need to, use `feof()` and `ferror()` to sort out what went wrong.
If you really, really insist on using feof(), then you also need to check your I/O operation:
while (!feof(file_para))
{
if (fgets(string, sizeof(string), file_para) == 0)
break;
...do printing, etc...
}
Note that you might be failing because ferror(file_para) evaluates to true even when feof(file_para) does not...so maybe you need while (!feof(file_para) && !ferror(file_para)), but that really is just more evidence that the while loop should be conditioned on the I/O function, not feof().
This is a common anti-pattern:
while (!feof(file_para))
{
fgets(string, 400, file_para);
feof() does not detect if the next input call will fail due to end-of-file; it tells you if the file has already reached end-of-file. You should only call it after an input function has already failed, to see why it failed (which could be either an error or end-of-file).
The correct pattern is:
while (fgets(string, 400, file_para))
{
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.
Soo... I saw a guy claim this code was working on another question.
while(scanf("%X", &hex) != EOF) {
//perform a task with the hex value.
}
So, in what context does the EOF flag get thrown? I though it would just keep asking for a number indefinitely. I added another line of code to test it, and it does exactly what I expected it too.....
This isn't a file, this seems to be stdin. So.... WHEN is this code useful?
Ie, in what context is the EOF return thrown?
If you look at the documentation for scanf, you will read that the value EOF is returned if a read failure occurred before the first value was assigned. (ie end of file)
http://en.cppreference.com/w/cpp/io/c/fscanf
You could equally test:
while(scanf("%X", &hex) == 1)
This is my preference. I expect one input, so I will be explicit.
Realistically speaking, this input is good on linux because ^d will end the stream, thus throwing the 'error.'
On windows, this behavior is different... whatever it is is not ctrl+d. At least I know now though, since I use both.
Thanks!
EOF is returned on I/O error and end-of-file. With stdin, an I/O error is a rare event and with keyboard input the end-of-file indication usual takes a special key sequence.
A practical use occurs with redirected input.
Assume a program exists that reads hexadecimal text and prints out decimal text:
// hex2dec.c
#include <stdio.h>
int main(void) {
unsigned hex;
int cnt;
while((cnt = scanf("%X", &hex)) == 1) {
printf("%u\n", hex);
}
// At this point, `cnt` should be 0 or EOF
if (cnt != EOF) {
puts("Invalid hexadecimal sequence found.");
return 1;
}
return 0;
}
// hex.txt contents:
abc
123
Conversion occurs with the command
hex2dec < hex.txt
2748
291
By detecting EOF on the stdin, the program knows when to return.