如何修复 scanf 将数据放入数组中?

0 c scanf

有人可以就 scanf 提出建议吗?“message”是一个 4 行 x 16 列的数组。用户输入数字(全部为 1 位整数)后,按“Enter”键时会出现错误消息。正如所说 - 可能与 scanf 有关。

for (int i = 0; i < M; i++) {
        for (int j = 0; j < columns; j++) {
            scanf("%d", message[i][j]);
        }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*mit 7

scanf 看起来是一种很好、简单、容易、方便的读取输入的方式。在某些方面确实如此,但事实证明,正确使用它可能非常困难,而且充满了陷阱。

\n

一开始您可能不想了解所有scanf错综复杂的事情。因此,现在,这里有一些安全使用 \ 功能子集的指南。scanf(出于我无法理解的原因,每个人都告诉初学者使用scanf,但没有人同时教授这样的规则。)

\n
    \n
  1. 请记住始终&在您尝试读取的变量前面使用。(这是一条特殊规则,仅供参考。例如,scanf不要尝试&在传递给 的变量上使用该规则。)printf
  2. \n
  3. 规则 1 的例外:在读取字符串时不要使用&%s
  4. \n
  5. 如果您正在使用 读取字符串%s,请确保您读入的变量是一个对于用户可能键入的内容来说足够大的字符数组,或者是一个指向对于malloc什么内容来说足够大的内存的指针。用户可能会打字。(另请参阅下面有关避免溢出的注释。)
  6. \n
  7. 请注意,读取%s包含空格字符的字符串。您不能用来读取可能包含空格的字符串(如全名)。(现在,请不要担心如何读取可能包含空格的字符串。另请参阅规则 14。)%s
  8. \n
  9. 不要尝试在同一程序中一起使用scanfand fgets(或过时的)。gets
  10. \n
  11. 不要尝试在同一个程序中同时使用scanfand 。getchar
  12. \n
  13. 尝试将自己限制为仅使用格式说明符%d%s%f%lf来分别读取int、 string 类型的变量(参见规则 3)float、 和double
  14. \n
  15. 如果你想将一个字符读入类型的变量中char,你可以使用" %c",但是神秘的额外显式空格字符至关重要。
  16. \n
  17. %仅在格式字符串中使用一个符号来读取一个变量。不要尝试在一次scanf调用中读取两个或多个变量。
  18. \n
  19. 始终检查scanf\ 的返回值。如果它返回 0 或负值EOF,则意味着它没有成功读取任何内容。如果返回1,则表示成功读取一个值。(如果您违反规则 9,并尝试读取多个值,它将返回成功读取的值的数量,介于 0 和您要求的数量之间的任何位置。)
  20. \n
  21. 如果scanf返回 0 或EOF,表明用户没有输入有效值,则打印一条错误消息并退出。不要尝试编写要求用户重试的代码,因为用户的错误输入仍然保留在输入流中,并且没有好的、简单的方法来消除它。(如果您确实想编写用户友好的代码,在出现错误时重新提示,scanf那么这不是适合该工作的工具。)
  22. \n
  23. 切勿在格式字符串后添加空格。这包括换行符\\n。(即,使用"%d",而不是"%d ""%d\\n"。)
  24. \n
  25. 不要尝试使用%[\xe2\x80\xa6]说明符。
  26. \n
  27. 如果您违反了规则 13(可能是因为有人告诉您这%[\xe2\x80\xa6]可能是读取包含空格或整行的字符串的一种方法),请不要其后面添加s。格式是%[\xe2\x80\xa6],不是%[\xe2\x80\xa6]s
  28. \n
\n

这些规则可能看起来有限制性,但是如果您遵循这些规则,您应该能够简单、轻松、可靠地将简单的输入输入到您的简单程序中,这就是这里的目标。 scanf否则会非常难以使用,经验表明,往往会出现 17 个不同的令人恐惧的令人沮丧的问题,而尝试解决这些问题完全是不必要的干扰,无法干扰您通过编写简单的 C 程序来学习 C 的目标。

\n

当您使用%sor读取字符串时%[\xe2\x80\xa6],存在危险:无论malloc您正在读入的数组或缓冲区有多大,用户可能会输入比这更多的内容。%19s为了避免溢出,您可以使用诸如显式告知scanf允许读取多少个字符之类的格式。(记住减去 1,为终止 留出空间\'\\0\'。也就是说,您可以用来%19s读入char str[20];or char *p = malloc(20);。)

\n

这些规则有点多。有关更简单的规则集,请参阅此答案。将规则 7、8、9、12 和 13 放在一起,实际上只有五个完整的格式字符串可以与scanf: "%d", "%s", "%f", "%lf", 或 一起使用" %c"。(但是没有逗号,没有固定字符串,除了 中的显式空格之外没有空格" %c",没有别的。) 例外:如上所述,可以使用类似的东西%19s来限制正在读取的字符串的长度。

\n

如果您需要做一些在遵守这些规则的情况下无法完成的更复杂的事情,那么是时候执行以下任一操作:

\n
    \n
  1. 充分了解如何scanf真正起作用(以及不起作用),以便您可以尝试做您想做的事情,但不会陷入这 17 个问题之一,或者
  2. \n
  3. 了解如何使用比 更好、更强大的方法scanf进行输入,也许可以通过使用读取整行fgets然后解析它们。
  4. \n
\n

  • @hyde它们是很好的指导方针,因为当你对这些函数有足够的了解以便能够混合它们时,你已经了解到“scanf”比它的价值更麻烦,并且混合不会有任何问题,因为你赢了根本不使用“scanf”。 (2认同)