2

I have to read a line like this:

0.000000 0.000000 -1.000000 -1.000000 0.230392 0.562016 -1.000000 -1.000000

Using strtok() and a while loop, I'm trying to extract each float numer and store it on my program. There is a problem when converting the token to a floating point number. This is my code:

double p;
char* token = strtok(line, " ");
while (token) {
    p = atof(token);
    printf("atof('%s') = %f\n", token, p);
    token = strtok(NULL, " ");
}

It outputs:

atof('0.000000') = 0,000000
atof('0.000000') = 0,000000
atof('-1.000000') = -1,000000
atof('-1.000000') = -1,000000
atof('0.230392') = 0,000000 <<<---- ???????????
atof('0.562016') = 0,000000 <<<---- ???????????
atof('-1.000000') = -1,000000
atof('-1.000000') = -1,000000

See the problem? Why does atof return 0 when passing a string number between 0 and 1?

TheUnexpected
  • 3,077
  • 6
  • 32
  • 62
  • 8
    I see that your printf is using "," as decimal point, but the input has ".". Could that be an issue? The output is consistent with atof converting only up to the ".". – Patricia Shanahan Oct 03 '13 at 13:54
  • @PatriciaShanahan so, the solution - using separator defined in [locales](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_19.html) OR writing Your own custom parser? – Kamiccolo Oct 03 '13 at 13:58
  • The printf is actually a [g_printf](https://developer.gnome.org/glib/2.28/glib-String-Utility-Functions.html). It can't be so different from the original printf – TheUnexpected Oct 03 '13 at 13:58
  • 2
    The source code you wrote in the question is not the source code you used to produce the sample output. The line containing `strtok` has a syntax error, and `token` is never changed in the loop, so the loop would continue forever printing the same value. You should show a [short, self-contained, compilable example](http://sscce.org). – Eric Postpischil Oct 03 '13 at 14:03
  • Yes, sorry but I made those mistakes when trying to simplify the whole code – TheUnexpected Oct 03 '13 at 14:07

2 Answers2

7

atof() (more specifcally, strtod()) is locale-dependant. Your locale uses , to signify a decimal, while the input string uses . to specify a decimal point. Since atof() stops parsing at the first non-valid character, it returns 0.

The simple fix is to change either your computer's locale to a different locale, or change the input strings.

EDIT: You could update the input string like this:

void update_string(char *str) {
    char *p = str;
    while(*p != '\0') {
        if(*p == '.')
            *p = ',';
        p++;
    }

This is a fairly temporary (and ugly) solution. The prefered solution is to change your locale. You could do it permanently (consult your distro's documentation) or temporarily.

To do it temporarily by just putting LC_NUMERIC="C" in front of the command. So if your compiled program is called a.out, you would execute it using:

LC_NUMERIC="C" ./a.out

or by using setlocale() in your main() function.

cyphar
  • 2,840
  • 1
  • 15
  • 25
  • I don't think atof is even seeing an error. Rather, it sees a character, ".", that is not part of the format it is interpreting as marking the end of the number. – Patricia Shanahan Oct 03 '13 at 14:05
  • 2
    Is there a simpler solution rather than replace the locale or change the string? My code must be locale-indipendent (moreover, the input string can't change) – TheUnexpected Oct 03 '13 at 14:11
  • 3
    @alessandro.francesconi Adding `#include ` and the line `setlocale (LC_NUMERIC, "C");` at the beginning of your `main` should set the decimalpoint to the `.` character. – halex Oct 03 '13 at 14:20
5

The decimal point for atof is locale dependent. In your locale the decimal point seems to be , causing the the parsing to end at the ..

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82