Search code examples
cfloating-pointatof

Why this atof() returns 0.0 for non-0.0 string numbers?


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?


Solution

  • 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.