6

Sorry for the simple question, but I'm trying to find an elegant way to avoid my program seeing input like "14asdf" and accepting it just as 14.

if (sscanf(sInput, "%d", &iAssignmentMarks[0]) != 0) 

Is there an easy way to prevent sscanf from pulling integers out of mangled strings like that?

3
  • You mean is there a way to have sscanf only pick up the numeric characters in a string like that? You might also want to clarify whether you want "53sd2" to return 53 or 532. Commented Jan 12, 2012 at 21:13
  • Sorry I should be more clear, I want "14asdf" to be recognized as invalid input, as would "53sd2". I only want to recognize integers that stand alone (at least space delimited) with no non-digit characters touching them. Commented Jan 12, 2012 at 21:23
  • This would be easy in C++. Maybe the 'c++' tag should be removed from this question? @AdamWathan, do you want only answers that work in C? Commented Jan 13, 2012 at 0:44

5 Answers 5

3

You can't directly stop sscanf() from doing what it is designed and specified to do. However, you can use a little-known and seldom-used feature of sscanf() to make it easy to find out that there was a problem:

int i; if (sscanf(sInput, "%d%n", &iAssignmentMarks[0], &i) != 1) ...failed to recognize an integer... else if (!isspace(sInput[i]) && sInput[i] != '\0') ...character after integer was not a space character (including newline) or EOS... 

The %n directive reports on the number of characters consumed up to that point, and does not count as a conversion (so there is only one conversion in that format). The %n is standard in sscanf() since C89.

For extracting a single integer, you could also use strtol() - carefully (detecting error conditions with it is surprisingly hard, but it is better than sscanf() which won't report or detect overflows). However, this technique can be used multiple times in a single format, which is often more convenient.

Sign up to request clarification or add additional context in comments.

Comments

2

You want to read integers from strings. It is easier to do this with strtol instead of sscanf. strtol will return, indirectly via endptr, the address just after the last character that was succesfully read into the number. If, and only if, the string was a number, then endptr will point to the end of your number string, i.e. *endptr == \0.

char *endptr = NULL; long n = strtol(sInput, &endptr, 10); bool isNumber = endptr!=NULL && *endptr==0 && errno==0; 

(Initial whitespace is ignored. See a strtol man page for details.

2 Comments

I added some text to the answer in order to explain the code. I hope you don't mind @Serge-appTranslator. Feel free to edit further or remove it.
What? text? Why not commenting the code while you're at it! :-) Thanks Aaron
2

This is easy. No fancy C++ required! Just do:

char unusedChar; if (sscanf(sInput, "%d%c", &iAssignmentMarks[0], &unusedChar) == 1) 

Comments

0

scanf isn't that smart. You'll have to read the input as text and use strtol to convert it. One of the arguments to strtol is a char * that will point to the first character that isn't converted; if that character isn't whitespace or 0, then the input string wasn't a valid integer:

char input[SIZE]; // where SIZE is large enough for the expected values plus // a sign, newline character, and 0 terminator ... if (fgets(input, sizeof input, stdin)) { char *chk; long val = strtol(input, &chk, 10); if (*chk == NULL || !isspace(*chk) && *chk != 0) { // input wasn't an integer string } } 

2 Comments

The question is about sscanf, not scanf, and hence the data is already in a string. See @Serge's answer.
This isn't correct: you can use [fs]scanf() for this OK: you just need to attempt reading something after the number and check the number of elements read.
0

If you can use c++ specific capabilities, there are more clear ways to test input strings using streams.

Check here: http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.2

If you're wondering, yes this did come from another stack overflow post. Which answers this question: Other answer

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.