fscanf reads the last integer twice - c

I have the following simple program to read from a text file (num.txt). The text file has numbers 1 2 3 4 5 in each line. When I run the program, it prints 5 twice. Can anybody tell me why is this happening, and how to fix it? thanks in advance
int main(void)
{
int number;
FILE *file;
int i = 0;;
file = fopen("num.txt", "r");
while (!feof(file)){
fscanf(file, "%d", &number);
printf("%d\n", number);
}
return 0;
}
Here's my text file num.xtx
1
2
3
4
5
And here's the program output
1
2
3
4
5
5
There is an extra 5

From the man page of scanf family of functions,
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the error
indicator for the stream is set, and errno is set to indicate the
error.
This means that the last successful fscanf call reads the last line from the stream file after which the while loop condition !feof(file) is true because the end of file condition is not met yet. This means the loop is executed one extra time and the previous value of the variable number is printed again.
Please read this - while(!feof(file)) is always wrong
You should check the return value of scanf instead of checking the end of file indicator on the file stream.
#include <stdio.h>
int main(void) {
int number;
FILE *file = fopen("num.txt", "r");
// check file for NULL in case there
// is error in opening the file
if(file == NULL) {
printf("error in opening file\n");
return 1;
}
// check if fscanf call is successful
// by checking its return value for 1.
// fscanf returns the number of input
// items successfully matched and assigned
while(fscanf(file, "%d", &number) == 1)
printf("%d\n", number);
return 0;
}

The second time fscanf failed and didn't write anything to number, that's why it's still 5 from the last time. To know if fscanf succeeded, you have to check its return value.
fscanf returns the number of arguments that it wrote. In your case, if it returns 1, it worked; if it returns 0, it didn't. This is what you should check instead of feof.
while (fscanf(file, "%d", &number) == 1)
{
printf("%d\n", number);
}

Related

How to stop reading a txt file at the end of it

I'm writing a C program which reads a text file line by line with a certain format to it.
I made a do { ... } while(!feof(file)); loop but it always loops one too many times. This is an issue because I have made it so that when my program expects to read something but gets nothing, it throws an error, so now it is throwing an error every time because it reaches the end of the file at the top of my loop.
I figured this is because the eof flag is triggered only once you try to fscanf something but there is nothing there. How can I fix this problem? Putting a final fscanf at the bottom doesn't work because if it's not at the end of the file, it will mess all the readings up and shift everything by one.
do {
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
// Read grades
read = fscanf(/*...*/);
if (read != 3)
{
return -1;
}
// Read student kind
int student_kind = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
if (student_kind < 0 | student_kind > 2)
{
printf("Invalid student kind");
return -1;
}
SCIPER sciper_teammate = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
} while (!feof(file));
Since you are using fscanf():
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]"); //here discarding unread characters in the buffer
} while(!feof(stdin) && !ferror(stdin));
This should work in your case but personaly. I don't like this approach since if you input less values than what fscanf is expecting this will fail, normaly resulting in an infinite loop.
My approach when reading formated input, is to check the inputed values.
For a sample input of 2 integers you can do something like:
Live sample
#include <stdio.h>
int main()
{
int a, b;
FILE* file;
if(!(file = fopen("file.txt", "r"))){
return 1;
}
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
printf("%d %d\n", a, b);
}
}
This addresses all input failures and will end the cycle for I/O error, for EOF and for bad inputs.

My program creates a file named date.in but it is not inserting all the numbers

Write a C program that reads from the keyboard a natural number n
with up to 9 digits and creates the text file data.out containing the
number n and all its non-zero prefixes, in a single line, separated by
a space, in order decreasing in value. Example: for n = 10305 the data
file.out will contain the numbers: 10305 1030 103 10 1.
This is what I made:
#include <stdio.h>
int main()
{
int n;
FILE *fisier;
fisier=fopen("date.in","w");
printf("n= \n");
scanf("%d",&n);
fprintf(fisier,"%d",n);
while(n!=0)
{
fisier=fopen("date.in","r");
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
}
Few things:
Function calls may return error. You need to check that every time.
fisier=fopen("date.in","w");
This should have been followed by an error check. To understand more on what it return, first thing you should do is read the man page for that function. See man page for fopen(). If there is an error in opening the file, it will return NULL and errno is set to a value which indicates what error occurred.
if (NULL == fisier)
{
// Error handling code
;
}
Your next requirement is separating the numbers by a space. There isn't one. The following should do it.
fprintf(fisier, "%d ", n);
The next major problem is opening the file in a loop. Its like you are trying to open a door which is already open.
fisier=fopen("date.in","r");
if(NULL == fisier)
{
// Error handling code
;
}
while(n!=0)
{
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
A minor issue that you aren't checking is the number is not having more than 9 digits.
if(n > 999999999)
is apt after you get a number. If you want to deal with negative numbers as well, you can modify this condition the way you want.
In a nutshell, at least to start with, the program should be something similar to this:
#include <stdio.h>
// Need a buffer to read the file into it. 64 isn't a magic number.
// To print a 9 digit number followed by a white space and then a 8 digit number..
// and so on, you need little less than 64 bytes.
// I prefer keeping the memory aligned to multiples of 8.
char buffer[64];
int main(void)
{
size_t readBytes = 0;
int n = 0;
printf("\nEnter a number: ");
scanf("%d", &n);
// Open the file
FILE *pFile = fopen("date.in", "w+");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
while(n != 0)
{
// Append to the file
fprintf(pFile, "%d ", n);
n = n / 10;
}
// Done, close the file
fclose(pFile);
printf("\nPrinting the file: ");
// Open the file
pFile = fopen("date.in", "r");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
// Read the file
while((readBytes = fread(buffer, 1, sizeof buffer, pFile)) > 0)
{
// Preferably better way to print the contents of the file on stdout!
fwrite(buffer, 1, readBytes, stdout);
}
printf("\nExiting..\n\n");
return 0;
}
Remember: The person reading your code may not be aware of all the requirements, so comments are necessary. Secondly, I understand english to a decent level but I don't know what 'fisier' means. Its recommended to name variables in such a way that its easy to understand the purpose of the variable. For example, pFile is a pointer to a file. p in the variable immediately gives an idea that its a pointer.
Hope this helps!
To draw a conclusion from all the comments:
fopen returns a file handle when successfull and NULL otherwise. Opening a file twice might result in an error (it does on my machine), such that fisier is set to NULL inside the loop. Obvioulsy fprintf to NULL wont do anything.
You only need to call fopen once, so remove it from the loop. After that it will work as intended.
It's alwas good to check if the fopen succeeded or not:
FILE *fisier;
fisier=fopen("date.in","w");
if(!fisier) { /* handle error */ }
You print no spaces between the numbers. Maybe that's intended, but maybe
fprintf(fisier,"%d ",n);
would be better.

C - Using fscanf to read '-1' from a file

I'm a bit new to C, but basically I have a problem where I need to read '-1' from a file. Sadly this means I run into a premature ending of the file, because the EOF constant is also -1 in my compiler.
What sort of work arounds would there be for this? Is there another function I can use to read it that will change the EOF to something I can work with?
Thanks in advance.
The code since people are asking for it
int read() {
int returnVal; // The value which we return
// Open the file if it isn't already opened
if (file == NULL) {
file = fopen(filename, "r");
}
// Read the number from the file
fscanf(file, "%i", &returnVal);
// Return this number
return returnVal;
}
This number is then later compared to EOF.
Okay this is probably bad practice, but I changed the code to the following
int readValue() {
int returnVal; // The value which we return
// Open the file if it isn't already opened
if (file == NULL) {
file = fopen(filename, "r");
}
// Read the number from the file
fscanf(file, "%i", &returnVal);
if (feof(file)) {
fclose(file);
return -1000;
}
// Return this number
return returnVal;
}
Because I knew I would never read any such number from my file (they range from about [-300, 300]. Thanks for all your help guys!
The return value of fscanf is NOT the value that was read, but rather it is the number of items successfully read, or EOF if an error occurred.
The problem is that your read function doesn't distinguish between a successful read and an error condition. You should change it to accept a int * as a parameter that scanf writes into, and the function should return something like 0 on a successful read and -1 on error. You can use the return value of scanf as the basis of what your function returns.
Also, there's a system call named read, so you should really name it something else. And don't forget to fclose(file) at the end of the function, otherwise you're leaking file descriptors.

feof detecting false end of file

I asked a different question about this earlier, but I was way off base about the problem so I've created a new question as I'm asking an entirely different question.
I have a function that reads a given line in a text file (given by ac variable). It performs the read of the line and then checks if that was the last line in the file. If so it increments a value.
The problem is that it's incremented the value even when it's not the actual end of the file. I think I'm using feof wrong but I've had no luck getting it to work:
int readIn(TinCan* inCan, int toggle)
{
int ii, isFinished = 0;
char fullName[20];
sprintf(fullName, "Label_%d.txt", inCan->pid);
FILE* fp;
fp = fopen(fullName, "r");
if(fp==NULL)
{
printf("Error: could not open %s\n", fullName);
}
else
{
for (ii=0; ii < ((inCan->ac)-1); ii++)
{
fscanf(fp, "%*d %*d %*d\n"); /*move through lines without scanning*/
}
fscanf(fp,"%d %d %d", &inCan->ac, &inCan->state, &inCan->time);
}
if (feof(fp) && (toggle == 1))
{
printf("File ended");
writeLog(inCan);
isFinished = 1;
terminated++;
}
fclose(fp);
return finished;
}
Sample data as requested, this is a text file I may use:
1 1 30
2 2 5
3 1 1
fscanf correctly assigns the values. On the second line, feof returns true and terminated is incremented. feof returns true again for the 3rd line and increments terminated a second time.
feof() does not detect if the file has ended. It detects if the last read error was due to the file having ended.
feof() only happens after a failed read.
So, first read data and check the return value. If the read failed use feof() to make sure it failed because the END-OF-FILE was reached (other reasons for the read to fail are error of some kind (network down, bad sector, printer on fire, ...), detectable with ferror()).
It's hard to tell without knowing the data format, but
fscanf(fp,"%d %d %d", &inCan->ac, &inCan->state, &inCan->time);
will read 3 values, but on the last line, it won't have read the end of line character, so it's not the end of the file.
Try:
fscanf(fp,"%d %d %d\n", &inCan->ac, &inCan->state, &inCan->time);

file handling in c : can not read proper in table format data

#include <stdio.h>
int main(void)
{
clrscr();
FILE *fin;
fin=fopen("data.txt","r");
if(fin==NULL)
{
printf("can not open input fil");
return 0;
}
long data[2];
while(!feof(fin))
{
fscanf(fin,"%ld %ld",&data[0],&data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
fclose(fin);
return;
}
above is my c code for reading a table from a file.In that ..last value is printing 2 times !!!
data.txt
1 34
2 24
3 45
4 56
5 67
but I can not get proper values with broken table like below...How can I resolve it ? (here It should work where it does not find any value it should return "null space" or zero ..but not the next value..)
data.txt
1 34
2
3 45
4
5 67
as well as
data.txt
1 34
57
3 45
4
5 34
above is my c code for reading a table from a file.In that ..last value is printing 2 times !!!
The last value is printing two times due to the structure of the file reading loop. The eof() flag is not set until an attempt is made to read past the end of the file. When fscanf() reads the last two longs from the last line of the file eof() is not yet set but the next call to fscanf() fails and sets eof() but the result of fscanf() is not queried immediately, resulting the use of the previously extracted longs: check the result of all read operations immediately.
A possible solution is to read a line at a time, using fgets(), and then use sscanf() to extract the long value(s) from the read line. If fscanf() is used, it would read past the new-line character to locate the second requested long, which is not the desired behaviour.
For example:
char line[1024];
while (fgets(line, 1024, fin))
{
/* Assign appropriate default values.
sscanf() does not modify its arguments
for which it has no value to assign.
So if 'line' has a single long value
data[1] will be zero. */
long data[2] = { 0, 0 };
/* You can use 'result' if you require to take particular
action if it reads only 1, or 0, items. */
int result = sscanf(line, "%ld %ld", &data[0], &data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
(in response to question update) To differentiate between lines where second value is missing:
2
and lines where first value is missing:
57
a valid range (or some other criteria) is required to determine which value (the first or second) was missing from the line:
int result = sscanf(line, "%ld %ld", &data[0], &data[1]);
if (1 == result)
{
if (data[0] >= 1 && data[0] <= 9)
{
printf("\n%ld 0", data[0]);
}
else
{
/* Read value was the second value. */
printf("\n%ld %ld", ++last_first_value, data[0]);
}
}
where last_first_value is a long that stores the current value of the first value (either the last successfully read first value or computed from the last successfully read first value).
while(!feof(fin))
{
fscanf(fin,"%ld %ld",&data[0],&data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
feof doesn't return true until after you attempt to read past the end of the file, so the loop will execute once too often. It's better to check the return value of fscanf and if it doesn't match what you expect (2 in this case), then check for EOF. Here's one possible restructuring:
int good = 1;
while (good)
{
int itemsRead = fscanf(fin, "%ld %ld", &data[0], &data[1]);
if (itemsRead == 2)
{
// process data[0] and data[1] normally
}
else
{
good = !good;
if (feof(fin))
printf("Hit end of file\n");
else if (ferror(fin))
printf("Error during read\n");
else
printf("Malformed input line\n");
}
}

Resources