如何正确安全地使用sscanf
首先,关于sscanf
使用的其他问题没有回答我的问题,因为常见的答案是根本不使用sscanf
而是使用fgets
或getch
,这在我的情况下是不可能的。
问题是我的C教授要我在程序中使用scanf
。 这是一项要求。 但是程序也必须处理所有不正确的输入。
程序必须读取整数数组。 以什么格式提供数组的整数并不重要。 为了使任务更容易,程序可能首先读取数组的大小,然后读取每行中的整数。
程序必须处理这些输入(并适当地报告错误):
- 999999999999999 … 9(数字大于整数)
- 12a3(不要将其读作整数12)
- a … z(字符串)
- 11 aa 22 33 \ n所有在一行(这可能通过丢弃11之后的所有内容来处理)
- 输入大于输入数组
可能有更多不正确的案例,这些是我能想到的唯一案例。
如果提供了错误输入,程序必须要求用户再次输入,直到给出正确的输入,但必须保留先前正确的输入(只有输入流中必须清除不正确的输入)。
一切都必须符合C99标准。
scanf
系列函数不能安全使用,尤其是在处理整数时。 你提到的第一个案例特别麻烦。 标准说明了这一点:
如果此对象没有适当的类型,或者无法在对象中表示转换结果 ,则行为未定义。
干净利落。 您可能会想到%5d
技巧等,但您会发现它们不可靠。 或许有人会想到错误。 不需要 scanf
函数来设置errno
。
按照这个有趣的小页面 :他们最终放弃了scanf
。
那么回到你的C教授那里问他们: C99究竟如何强制sscanf报告错误 ?
好吧,让sscanf接受所有输入为%s(即字符串),然后对它们进行程序分析
如果你必须使用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
变体。