AugustoQ AugustoQ - 1 month ago 7
C Question

Trouble reading from file

So I think this should be pretty straight forward. I actually can't even understand what could possibly be going wrong, and that's what bugs me the most.

Here's the deal: I have to read a couple of numbers from a file, but these numbers are in scientific notation. An example file would have the numbers like this:

1.00090E+00,2.90000E+00


So I thought I'd simply read it like this: get a double, ignore a character, get an int, ignore a character, get another double, ignore a character, and get a final int, so for this example, it would:

get (1.00090)
ignore (E)
get (+00)
ignore (,)
get (2.90000)
ignore (E)
get (+00)


So, I wrote these fscanf:

fscanf(arquivo, " %lf%*c%d%*c", &mantissa1, &expoente1);
x[i] = numToFloat(mantissa1, expoente1);
fscanf(arquivo, "%lf%*c%d", &mantissa2, &expoente2);
fx[i] = numToFloat(mantissa2, expoente2);


I separated them to make the understanding simpler. But then, it doesn't work. It reads the first double correctly, but then it messes up the int. And then it messes up everything on the second fscanf.
I tried all that I could think of. Put the formatted string onto the fscanf (
"%lfE%d,"
and
"%lfE%d"
). To read the signal into a character variable (
"%lf%*c%c%d%*c"
). None of it works.

Any guesses as to what's wrong?

Answer

First, you do not need to parse the mantissa and exponent separately. scanf natively understands n.nnnEĀ±nnn notation. This is why your format string doesn't behave as you expect; the %lf directive consumes the entire first number including the E+00 piece, then %*c consumes the comma, %d the 2, and now we're hopelessly out of sync.

Second, you should not use any of thescanf functions, ever. Instead, read a line at a time with fgets (or getline, if you have it), split it on commas with strtok, and convert numbers to binary with strtod (which also natively understands scientific notation). This will be more coding up front, but the result will be easier to read and debug, it will be easier to make it robust against malformed input, and it will have well-defined behavior on input overflow.

(Technically you do not need to use strtok, as strtod will tell you where each number ends, but it is conceptually simpler to do the splitting first.)

Comments