Scanf:检测输入太长

时间:2017-01-06 16:34:38

标签: c input scanf

我们可以轻松限制scanf接受的输入长度:

char str[101];
scanf("%100s", str);

有没有有效的方法可以找出字符串被修剪过的?例如,我们可以在这种情况下报告错误。

我们可以将"%101s"读入char strx[102]并与strlen()核对,但这会产生额外费用。

4 个答案:

答案 0 :(得分:4)

使用%n转换将扫描位置写入整数。如果它在开头超过100,则字符串太大。

我发现%n对各种事物都很有用。

我认为以上内容对于那些阅读了scanf docs / man页面并且实际上已经尝试过的人来说是充足的信息。

我们的想法是让你的缓冲区和扫描限制大于你期望找到的任何大小的字符串。然后,如果您发现扫描结果与扫描限制一样大,则您知道它是无效字符串。然后你报告一个错误或退出或你做的任何事情。

另外,如果您要说"但我想报告错误并继续下一行,但scanf将我的文件留在未知位置。"
这就是您使用fgets一次阅读一行,然后使用sscanf代替scanf的原因。它消除了在行中间结束扫描的可能性,并且可以轻松计算错误报告的行号。

所以这是我刚写的代码:

#include <stdio.h>
#include <stdlib.h>

int scan_input(const char *input) {
        char buf[101];
        int position = 0;
        int matches = sscanf(input, "%100s%n", buf, &position);
        printf("'%s' matches=%d position=%d\n", buf, matches, position);
        if (matches < 1)
                return 2;
        if (position >= 100)
                return 3;
        return 0;
}

int main(int argc, char *argv[]) {
        if (argc < 2)
                exit(1);
        const char *input = argv[1];
        return scan_input(input);
}

以下是发生的事情:

  

$ ./a.out'这是一个测试字符串&#39;
  &#39;这&#39;匹配= 1位= 4   $ ./a.out'这是一个测试字符串&#39;
  &#39;这-is-a的测试字符串&#39;匹配= 1位= 21   $ ./a.out' 0123456789012345678901234567890123456789012556759012345678601234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789&#39;
  &#39; 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789&#39; matches = 1 position = 100

答案 1 :(得分:2)

您可以使用lst来读取整行。然后验证换行符是否在字符串中。但是,这有一些缺点:

  1. 它将消耗整条线,也许这不是你想要的。请注意fgets()不等同于fgets() - 后者仅在第一个空白字符出现之前读取;
  2. 如果在提供换行符之前关闭输入流,则您将不确定;
  3. 您必须通过数组搜索换行符。
  4. 所以更好的选择似乎是这样的:

    scanf("%100s")

    这会正常读取字符串并检查下一个字符。如果它是空白或者流已经关闭,那么所有内容都被读取。

    如果您不希望测试修改输入流,则会char str[101]; int c; scanf("%100s", str); c = getchar(); ungetc(c, stdin); if (c == EOF || isspace(c)) { /* successfuly read everything */ } else { /* input was too long */ } 。但这可能是不必要的。

答案 2 :(得分:1)

fgets()是一种更好的方法,阅读用户输入行,然后解析它。

但是OP仍然想要使用scanf() ....

因为无法检测到输入太长而且#34;在没有尝试读取超过n个最大字符的情况下,代码需要超越。

unsigned char sentinel;
char str[101];
str[0] = '\0';

if (scanf("%100s%c", str, &sentinel) == 2) {
  ungetc(sentential, stdin);  // put back for next input function
  if (isspace(sentential) NoTrimOccurred();
  else TrimOccurred();
 else {
   NoTrimOccurred();
 }

答案 3 :(得分:0)

执行此操作的一种非常粗略但简单的方法是在getchar()之后添加scanf()来电。

读取实际输入后,

scanf()newline留在输入缓冲区中。如果提供的输入 less 而不是最大字段宽度,getchar()将返回换行符。否则,将返回第一个未消耗的输入。

也就是说,理想的做法是实际读取比所需的值更多的内容,并查看缓冲区中是否有任何内容区域。您可以使用fgets(),然后检查100元素值是否为newline,但这也包含额外费用。< / p>