使用sscanf()忽略旁边有字符的整数

6

很抱歉这个问题有点简单,但我正在尝试找到一种优雅的方法来避免我的程序接受像"14asdf"这样的输入,并将其视为 14。

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

有没有一种简单的方法可以防止sscanf从被破坏的字符串中提取整数?


你的意思是有没有办法让sscanf只捕捉字符串中的数字字符?你可能还想澄清一下,你希望"53sd2"返回53还是532。 - Ian
抱歉,我应该更清楚地表达。我希望"14asdf"被识别为无效输入,就像"53sd2"一样。我只想识别独立的整数(至少以空格分隔),没有非数字字符与它们接触。 - ARW
这在C++中很容易。也许应该从这个问题中移除 'c++' 标签?@AdamWathan,你是否只想要适用于C的答案? - Aaron McDaid
5个回答

3

你不能直接阻止sscanf()执行其设计和规定的操作。但是,你可以使用sscanf()的一个鲜为人知且很少使用的功能来轻松发现问题:

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...
%n 指令报告了到该点为止所消耗的字符数,不算作转换(所以该格式中只有一个转换)。自C89以来,在sscanf()中,%n是标准的。 如果要提取单个整数,也可以使用 strtol() - 但要小心(用它检测错误条件非常困难,但它比sscanf()更好,因为它可以在单个格式中多次使用,这通常更方便。)

2

这很简单。不需要花哨的 C++!只需执行以下操作:

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

2

您希望从字符串中读取整数。使用strtol比使用sscanf更容易实现。 strtol将通过endptr间接返回最后一个成功读入数字的字符后面的地址。如果且仅当字符串是数字时,endptr将指向您的数字字符串的结尾,即*endptr == \0

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

(初始空格将被忽略。有关详细信息,请参见 strtol man页面。)

我在答案中添加了一些文本,以便解释代码。希望Serge-appTranslator不介意。随意进一步编辑或删除它。 - Aaron McDaid
1
什么?文本?为什么不趁机注释代码呢!:-) 谢谢Aaron - Serge Wautier

0

0

scanf 并不是很智能。您需要将输入作为文本读取,并使用 strtol 转换它。其中一个参数 strtol 是一个指向未转换字符的 char *;如果该字符不是空格或 0,则输入字符串无效:

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
  }
}

这个问题是关于 sscanf 而不是 scanf,因此数据已经在一个字符串中。请参考 @Serge 的回答。 - Aaron McDaid
这不是正确的:你不能使用[fs]scanf()来做到这一点。好的:你只需要尝试在数字后读取一些内容,并检查读取的元素数量。 - Dietmar Kühl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接