sscanf doesn't move, scanning same integer eve

2020-02-10 18:12发布

问题:

I have a string that has ints and I'm trying to get all the ints into another array. When sscanf fails to find an int I want the loop to stop. So, I did the following:

int i;
int getout = 0;
for (i = 0; i < bsize && !getout; i++) {
    if (!sscanf(startbuffer, "%d", &startarray[i])) {
        getout = 1;
    }
}
//startbuffer is a string, startarray is an int array.

This results in having all the elements of startarray to be the first char in startbuffer. sscanf works fine but it doesn't move onto the next int it just stays at the first position.

Any idea what's wrong? Thanks.

回答1:

The same string pointer is passed each time you call sscanf. If it were to "move" the input, it would have to move all the bytes of the string each time which would be slow for long strings. Furthermore, it would be moving the bytes that weren't scanned.

Instead, you need to implement this yourself by querying it for the number of bytes consumed and the number of values read. Use that information to adjust the pointers yourself.

int nums_now, bytes_now;
int bytes_consumed = 0, nums_read = 0;

while ( ( nums_now = 
        sscanf( string + bytes_consumed, "%d%n", arr + nums_read, & bytes_now )
        ) > 0 ) {
    bytes_consumed += bytes_now;
    nums_read += nums_now;
}


回答2:

You are correct: sscanf indeed does not "move", because there is nothing to move. If you need to scan a bunch of ints, you can use strtol - it tells you how much it read, so you can feed the next pointer back to the function on the next iteration.

char str[] = "10 21 32 43 54";
char *p = str;
int i;
for (i = 0 ; i != 5 ; i++) {
    int n = strtol(p, &p, 10);
    printf("%d\n", n);
}


回答3:

Convert the string to a stream, then you can use fscanf to get the integers. Try this. http://www.gnu.org/software/libc/manual/html_node/String-Streams.html



回答4:

This is the correct behavior of sscanf. sscanf operates on a const char*, not an input stream from a file, so it will not store any information about what it has consumed.

As for the solution, you can use %n in the format string to obtain the number of characters that it has consumed so far (this is defined in C89 standard).

e.g. sscanf("This is a string", "%10s%10s%n", tok1, tok2, &numChar); numChar will contain the number of characters consumed so far. You can use this as an offset to continue scanning the string.

If the string only contains integers that doesn't exceed the maximum value of long type (or long long type), use strtol or strtoll. Beware that long type can be 32-bit or 64-bit, depending on the system.