fscanf() skips the first line in text file [C]

Jul 28, 2013 at 12:59pm
I have a text file that contains simple account information like this:

1234567890
234567
345678.90

First line is a 10-digit account number. Second line is the 6-digit account PIN (it's a simple program, so no encryption needed yet, whatsoever), and the last is the account balance. Now, when I try to read the text file, it skips the first line (account number), only the PIN and the balance are printed out.

Also, I read in some articles that fscanf() returns a number "every time it reads a line in a document" (correct me if I'm wrong). So, for example:

fscanf(fp, "%s\n%s\n%ld", account, pin, balance);

If it reads the sample lines in the text file above, it would return 1, right (because it read 1 line that matched the format in the fscanf())? And will return a -1 once the EOF is reached, right?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void loadAccount(){
	char account[10];
	char pin[10];
	float balance;
	
	FILE *fp
	
	fp = fopen("/acctinfo.txt", "r+");
	
	if (fp != NULL) {
		while(fscanf(fp, "%s", account) != -1){
			fscanf(fp, "%s\n%s\n%f", account, pin, balance);
			
			printf("%s\n", account);
			printf("%s\n", pin);
			printf("%f\n", balance);
		}
	} else {
		printf("Account info not found.");
	}

	fclose(fp);	
	getch();	
}


EDIT:

I think the problem is with my while() condition. I removed it (turned into a comment) and was able to retrieve the right information from the text, with the exception of the balance. Here was the output:

1234567890
234567
345678.906250

Not sure where the .006250 came from.

EDIT 2:

I changed the while condition back to !feof(fp) and I was able to fetch the right content from the text file. But. I'd really want to implement this without using !feof() because, as said by many people from the forums here, it's wrong to use !feof()...
Last edited on Jul 28, 2013 at 1:18pm
Jul 28, 2013 at 1:26pm
From the C Standard

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.


As for your code then you are trying to read account twice. The first one is in the while condition and the second one in the next statement.

1
2
		while(fscanf(fp, "%s", account) != -1){
			fscanf(fp, "%s\n%s\n%f", account, pin, balance);
Last edited on Jul 28, 2013 at 1:27pm
Jul 28, 2013 at 1:30pm
I see, so that's why it "skipped" the first line. So, is it better for me to just use !feof in this case?
Jul 28, 2013 at 1:32pm
You can use feof. But in any case I think you should assign initial values for the elements that in case of EOF they would have some defined values.
Jul 28, 2013 at 1:42pm
By that, you mean initialize the variables yes? Okay, will do that. Then just one more question. When I try to run the following code,

1
2
3
4
5
6
7
8
9
10
void loadAccount(){
	...
	float balance = 0;
	...	
	if (fp != NULL) {
		while(!feof(fp)){
			fscanf(fp, "%s\n%s\n%f\n", &account, &pin, &balance);
			printf("%f\n", balance);
...
}


If for example, the balance variable should contain 345678.90, instead of printing the right value out, it always prints out 345678.906250. I don't understand why there is an additional .006250 in the value of the balance variable.
Last edited on Jul 28, 2013 at 1:46pm
Jul 28, 2013 at 1:59pm
The problem is that float types are unable to represent exactly the fraction part.
Jul 28, 2013 at 3:13pm
Never use
while(!feof(fp)){
, that's almost always an error.

Never use naked %s, you're begging to get hacked. Always specify the length of the buffer you're writing to. In fact, your example already involves overflow: the array "account" can hold only a 9 character C-string, while the string "1234567890" has ten.

Also, the \n's are redundant (both %f and %s skip leading whitespace)

Your initial approach (checking the result of fscanf) was much better, you just didn't check the result of the right scanf:

1
2
3
4
char account[11]; // enough to hold ten characters!
...
while( fscanf(fp, "%10s%9s%f", account, pin, &balance) == 3)
                printf("%s\n%s\n%f\n", account, pin, balance);
Last edited on Jul 28, 2013 at 3:14pm
Jul 28, 2013 at 4:10pm
@Cubbi: Sorry, since I'm a beginner at this, do you mind explaining what this line means?

 
"%10s%9s%f"


And how come only the balance has the & sigil in it? I tried adding & to account, pin and balance and the program /didn't/ run (or rather, it ended prematurely or something -- bottom line, didn't work).

@vlad from moscow: http://www.cplusplus.com/forum/beginner/107452/#msg582896

I don't know what you mean by this. Before, I would naturally be able to working with floating type points with ease. This is the first time I've encountered something this odd. Now, I tried getting the string counterpart instead, but when I try to use atof(), it either gives me a +NAN or some other random value.
Last edited on Jul 28, 2013 at 4:23pm
Jul 28, 2013 at 5:10pm
The compiler is unable to represent the fraction of number 345678.90 that is 90 exactly in memory. It can it do approximately.
If you will use for example function atof you will get the same result.

1
2
3
4
char s[] = "345678.90";
float x = atof( s );

printf( "%f", x );


As for your first question then this format specifier %10s points out that the function shall enter only 10 characters. All other characters will be ignored.
Jul 28, 2013 at 8:23pm
do you mind explaining what this line means?
"%10s%9s%f"

That line instructs fscanf to
1. read from file and ignore zero or more spaces, tabs, or newlines (whitespace)
2. read from file no more than 10 non-whitespace characters and store them in the array whose first element is pointed to the next argument to fscanf() (account in that case). Write a terminating zero to the array to make it a C string
3. same as 1
4. same as 2, but only 9 non-whitespace characters and the next argument is used (pin in this case)
5. same as 1
6. read from file the characters that form one of the recognized formats for floating-point numbers and store it in the float pointed to by the next argument

Read up on C I/O functions. They are complicated, you need to know exactly what each character means and does before running the program.

how come only the balance has the & sigil in it?

the %f specifier expects a pointer to a float. The address-of operator constructs one from the float object.

Read up on C operators.
Topic archived. No new replies allowed.