如何正确安全地使用sscanf

时间:2012-02-26 21:28:27

标签: c scanf

首先,关于sscanf用法的其他问题不回答我的问题,因为常见的答案是根本不使用sscanf并使用fgetsgetch相反,这在我的情况下是不可能的。

问题是我的C教授要我在程序中使用scanf。这是一个要求。 但是程序也必须处理所有不正确的输入。

程序必须读取整数数组。整数的格式无关紧要 为阵列提供。为了使任务更容易,程序可能首先读取数组的大小,然后读取每行中的整数。

程序必须处理这些输入(并适当地报告错误):

  1. 999999999999999 ... 9(数字大于整数)
  2. 12a3(不要将其读作整数12)
  3. a ... z(字符串)
  4. 11 aa 22 33 \ n全部在一行(这可能是通过在11之后丢弃所有内容来处理的)
  5. 输入大于输入数组
  6. 可能有更多不正确的案例,这是我能想到的唯一案例。

    如果提供了错误输入,程序必须要求用户再次输入,直到 给出了正确的输入,但必须保留先前的正确输入(仅限不正确的输入) 必须从输入流中清除输入。)

    一切都必须符合C99标准。

3 个答案:

答案 0 :(得分:10)

scanf函数族不能安全使用,尤其是在处理整数时。你提到的第一个案例特别麻烦。标准说明了这一点:

  

如果此对象没有合适的类型,或者的结果   转换无法在对象中表示,行为是   理解过程科幻奈德。

简单明了。你可能会想到%5d技巧等,但你会发现它们不可靠。或许有人会想到错误。 scanf函数不需要设置errno

关注此fun little page:他们最终完全放弃了scanf


回到你的C教授并问他们: C99如何确定sscanf会报告错误

答案 1 :(得分:1)

好吧,让sscanf接受所有输入为%s(即字符串),然后对它们进行程序分析

答案 2 :(得分:1)

如果您必须使用scanf接受输入,我认为您从以下内容开始。

int array[MAX];
int i, n;
scanf("%d", &n);
for (i = 0; i < n && !feof(stdin); i++) {
    scanf("%d", &array[i]);
}

这将处理(或多或少)自由格式输入问题,因为scanf在匹配%d格式时会自动跳过前导空格。

您关注的其他许多问题的关键观察是scanf告诉您它成功解析了多少格式代码。所以,

int matches = scanf("%d", &array[i]);
if (matches == 0) {
   /* no integer in the input stream */
}

我认为这直接涉及(3)和(4)

本身并不是处理输入12a3 的情况。第一次循环,scanf会解析'12 as an integer 12, leaving the remaining a3`以进行下一个循环。不过,下次你会得到一个错误。这对你教授的目的来说是否足够好?

对于大于maxint的整数,例如“999999 ....... 999”,我不确定你可以用直线scanf做什么。

对于输入大于输入数组,这不是scanf问题本身。您只需计算到目前为止已解析的整数数。

如果允许您使用sscanf来解码字符串,只需通过scanf("%s")之类的内容从输入流中提取字符串,您也可以执行以下操作:

while (...) {
    scanf("%s", buf);
    /* use strtol or sscanf if you really have to */
}

这适用于任何序列的空格分隔词,并允许您分别扫描单词的输入,然后查看这些单词是否与数字相似。而且,如果必须,您可以为每个部分使用scanf变体。