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?

ARW
  • 3,306
  • 7
  • 32
  • 41
  • 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. – Ian Jan 12 '12 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. – ARW Jan 12 '12 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? – Aaron McDaid Jan 13 '12 at 00:44

5 Answers5

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
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.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
Serge Wautier
  • 21,494
  • 13
  • 69
  • 110
2

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

char unusedChar;
if (sscanf(sInput, "%d%c", &iAssignmentMarks[0], &unusedChar) == 1)
StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
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
  }
}
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • The question is about `sscanf`, not `scanf`, and hence the data is already in a string. See @Serge's answer. – Aaron McDaid Jan 13 '12 at 00:51
  • 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. – Dietmar Kühl Jan 13 '12 at 01:05
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

Community
  • 1
  • 1
Ian
  • 4,169
  • 3
  • 37
  • 62