5

I'm parsing a string (a char *) and I'm using sscanf to parse numbers from the string into double variables, like this:

while (*s) {
     if (sscanf(s, " %1[MmLl] %f %f %n ", command, &x, &y, &n) == 3) {
        //Do some processing
        s += n;
     }
}

This works for most of the inputs except few cases. The problem is with the count variable n. For some input, the variable n is never updated and it continues to hold the count of the previous iteration. This results in a wrong offset and mess up the parsing. I don't see anything weird with the input that is failing.

Note: This issue happens only in windows as the same code produces correct output in linux.

Has anyone faced similar issues?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Mugunth
  • 51
  • 1

3 Answers3

2

Get rid of the spaces before and after the %n.

ooga
  • 15,423
  • 2
  • 20
  • 21
1

We have noticed this with VS2010, but it seems to be fixed in VS2019. Also, the same format (with spaces around %n) seems to work on linux. So I would call this a Microsoft bug.

0

While the differing behavior on Windows and linux for the same input seems to be a bug in the Microsoft C library, please note some problems in the code:

  • if for some reason the input does not have exactly the expected form, the loop will iterate for ever trying to match from the same point.

  • the spaces before the %f and after the %n are redundant.

  • the space before the %n is not redundant and is probably useful to match trailing white space in the string, such as a newline.

Here is a modified version:

int parse_numbers(const char *str) {
    const char *s = str;
    while (*s) {
        char command[2];
        int n;
        if (sscanf(s, " %1[MmLl]%f%f %n", command, &x, &y, &n) == 3) {
            //Do some processing
            s += n;
        } else {
            fprintf(stderr, "invalid format: %.*s\n"
                            "                %*s\n",
                    (int)strcspn(str, "\r\n"), str, n,
                    (int)(s - str), "^");
            return -1;
        }
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189