【问题标题】:When the length of an input exceeds the size of a C string array, what are the options to deal with it?当输入的长度超过 C 字符串数组的大小时,有哪些处理方法?
【发布时间】:2020-02-22 05:25:11
【问题描述】:

用C编程语言,

我正在尝试读取字符串输入并将其存储到具有固定大小 [11] 的 char 数组中。

当我输入的字符超过 10 个时,其余字符被发送到下一个 scanf。

所以我的问题是,

  1. 有没有什么办法可以限制输入的大小?

  2. 或者,当输入超过一个char数组的大小时,有什么办法可以截掉剩下的字符,而不是发送到下一个scanf?

  3. 或者,我应该只知道要输入多少个字符吗?

  4. 或者,我应该创造条件来防止这个问题发生吗?

int main(void)
{
    char phoneNum[11];
    char password[11];

    printf("Enter the phone Number: ");
    scanf("%10s", phoneNum);

    printf("Enter the password: ");
    scanf(" %10s", password);

    printf("\n\n");
    //Display
    printf("Phone number: %s\n", phoneNum);
    printf("Password : %s\n", password);

    return 0;
}

/*
What I tried: 
-input: 
 Enter the phone Number: 123-456-7890
 Enter the password:    // This part has been skipped.

-output:
 Phone number: 123-456-78
 Password: 90


What I expected:
-input:
 Enter the phone Number: 123-456-7890
 Enter the password: asdf12386945648

-output:
 Phone number: 123-456-78
 Password: asdf123869
*/

【问题讨论】:

  • 为此使用scanf() 以外的其他内容。例如。使用fgets()getline() 读取整行,然后使用strtok() 在空白处将其拆分,并使用strncpy() 从每个标记复制到具有大小限制的目标数组。
  • 你正好违反了scanf 的限制。当它停止读取时,出于任何原因(例如因为它达到字符数),它总是将所有未读输入留在输入流中,以便读取格式字符串的下一部分,无论您是否愿意。
  • 您可以使用巧妙插入的%*s%*[...] 说明符来处理未读输入。 (* 表示扫描但分配给变量。)
  • 两个一般规则: (a) scanf 基本上是一个玩具。您可以将它用于定义明确的输入,但如果您想要优雅地处理“非法”输入(例如,用户应该只输入 10 个字符,但肆意输入更多),通常很难实现这种优雅在scanf 内处理。为了做得更好,您通常最好使用scanf 以外的其他东西。 (b) 最好将这些长度说明符视为限制目标数组的溢出,not 将用户的输入限制为您认为正确的某个确切值。 (更多在下一条评论中。)
  • 最好将%s 视为“读取任意长度的字符串”(尽管这最终会非常危险),而将%##s 视为“读取任意长度的字符串,但不要溢出我分配的这个希望足够大但最终大小固定的数组。”如果您想说的是“哟,用户,您不允许输入任意长度的字符串,您最多可以输入 N 个字符,就是这样 ", scanf 本身并不是这项工作的好工具。您最好阅读任意长度的字符串,然后作为第二步调用strlen 并进行投诉。

标签: c scanf c-strings


【解决方案1】:

有什么办法可以限制输入的大小吗?

不,代码不能阻止用户输入。相反,代码可能会限制保存的输入量,并可能在输入过多时消耗或退出。

或者,当输入超过一个char数组的大小时,有什么办法可以截掉剩下的字符,而不是发送到下一个scanf?

是的。最好不要将其发送到下一个输入函数。在这里处理你的问题。 一个简单的解决方案是

int read_input(char *destination, size_t sz) {
  if (sz > INT_MAX) sz = INT_MAX;
  if (fgets(destination, sz, stdin) == NULL) return EOF;
  size_t len = strlen(destination);
  if (len > 0 && destination[len-1] == '\n') { // lop off potential \n
    destination[--len]  = '\0';
  }
  if (len + 1 == sz) {  // if more input ...
    // let us consume it and toss it.
    int ch;
    while ((ch = fgetc(stdin)) != '\n' || ch != EOF) {
      ;
    }
    // Input exceeds expectations, take evasive action.
    // Maybe print an error message and try again?
    // For now, let us just exit.
    fprintf("Input too long\n");
    exit(EXIT_FAILURE);
  }
  return (int) len;
}    

或者,我应该只知道要输入多少个字符吗?

用户输入是邪恶的 - 期待最坏的情况。建议允许最大合法输入的 2 倍。除此之外,还有一些不好的事情发生了。

或者,我应该创造条件来防止这个问题发生吗?

无法阻止,只能应对错误或恶意的输入。


提示:在预期的输入大小方面要大方。 11 对于phoneNum[] 来说太小了。允许输入处理您可能期望的 2 倍,比如30然后限定输入。疯狂的输入长度是一种攻击。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 2015-10-16
    • 1970-01-01
    • 2020-01-10
    • 2013-05-02
    • 1970-01-01
    相关资源
    最近更新 更多