سؤال

I have the following c code

if (sscanf(input, "s %d\n", &value) == 1){}

Where it is suppose to parse the following

s -inf
....
s 0
s 1
s 2
....
s inf

but not such things as

s 5junkjunkjunk

Because it shouldn't match as there is something in between %d and the \n. Yet it does work even though it doesn't fit the format string.

هل كانت مفيدة؟

المحلول

This is (one of the) reasons why one should never use *scanf: it's ridiculously difficult to get it to handle malformed input robustly.

The correct way to parse something like this is: use fgets (or getline if you have it) to read an entire line, manually check for and skip over the leading "s ", then use strtod to parse the number, then check whether strtod set *endp to point to a newline.

If the syntax is even a little more complicated than what you have it may be time to reach for lex and yacc.

نصائح أخرى

If you read the docs for scanf(), you'll find that every appearance of a whitespace character in the format string matches any number of whitespace characters (including zero) in the input. sscanf() can't be forced to match an entire string -- it "succeeds" if it matches everything in the format string, even if this leaves other characters (junkjunkjunk) unconsumed.

After accept answer

inf is nicely read as a floating point.

Agree scanf() is cumbersome, but sscanf() is versatile.

Note: "%n" reports the number of char scanned and does not contribute to sscanf() result.

char buf[100];
if (fgets(buf, sizeof buf, input) == NULL) EOForIOerror();
int n;
double x;
if (sscanf("s %lf %n", &x, &n) != 1 || buf[n]) ScanFailure();
// if needed
if (!isinf(x) && round(x) != x) NumberIsNotInfinityNorWholeNumber(); 
// x is good to go

Details:

If no legit number is found, sscanf() does not return 1 and ScanFailure() is called.

Else is a legit number is found, " %n" scans any number 0 or more trailing white-spaces such as '\n'. Then it sets the offset of the scan in n. This location will be the first non-white-space after the number. If it is not '\0' then ScanFailure() is called.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top