有人可以就 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)
scanf
看起来是一种很好、简单、容易、方便的读取输入的方式。在某些方面确实如此,但事实证明,正确使用它可能非常困难,而且充满了陷阱。
一开始您可能不想了解所有scanf
错综复杂的事情。因此,现在,这里有一些安全使用 \ 功能子集的指南。scanf
(出于我无法理解的原因,每个人都告诉初学者使用scanf
,但没有人同时教授这样的规则。)
&
在您尝试读取的变量前面使用。(这是一条特殊规则,仅供参考。例如,scanf
不要尝试&
在传递给 的变量上使用该规则。)printf
&
%s
。%s
,请确保您读入的变量是一个对于用户可能键入的内容来说足够大的字符数组,或者是一个指向对于malloc
什么内容来说足够大的内存的指针。用户可能会打字。(另请参阅下面有关避免溢出的注释。)%s
包含空格字符的字符串。您不能用来读取可能包含空格的字符串(如全名)。(现在,请不要担心如何读取可能包含空格的字符串。另请参阅规则 14。)%s
scanf
and fgets
(或过时的)。gets
scanf
and 。getchar
%d
、%s
、%f
和%lf
来分别读取int
、 string 类型的变量(参见规则 3)float
、 和double
。char
,你可以使用" %c"
,但是神秘的额外显式空格字符至关重要。%
仅在格式字符串中使用一个符号来读取一个变量。不要尝试在一次scanf
调用中读取两个或多个变量。scanf
\ 的返回值。如果它返回 0 或负值EOF
,则意味着它没有成功读取任何内容。如果返回1,则表示成功读取一个值。(如果您违反规则 9,并尝试读取多个值,它将返回成功读取的值的数量,介于 0 和您要求的数量之间的任何位置。)scanf
返回 0 或EOF
,表明用户没有输入有效值,则打印一条错误消息并退出。不要尝试编写要求用户重试的代码,因为用户的错误输入仍然保留在输入流中,并且没有好的、简单的方法来消除它。(如果您确实想编写用户友好的代码,在出现错误时重新提示,scanf
那么这不是适合该工作的工具。)\\n
。(即,使用"%d"
,而不是"%d "
或"%d\\n"
。)%[\xe2\x80\xa6]
说明符。%[\xe2\x80\xa6]
可能是读取包含空格或整行的字符串的一种方法),请不要在其后面添加s
。格式是%[\xe2\x80\xa6]
,不是%[\xe2\x80\xa6]s
。这些规则可能看起来有限制性,但是如果您遵循这些规则,您应该能够简单、轻松、可靠地将简单的输入输入到您的简单程序中,这就是这里的目标。 scanf
否则会非常难以使用,经验表明,往往会出现 17 个不同的令人恐惧的令人沮丧的问题,而尝试解决这些问题完全是不必要的干扰,无法干扰您通过编写简单的 C 程序来学习 C 的目标。
当您使用%s
or读取字符串时%[\xe2\x80\xa6]
,存在危险:无论malloc
您正在读入的数组或缓冲区有多大,用户可能会输入比这更多的内容。%19s
为了避免溢出,您可以使用诸如显式告知scanf
允许读取多少个字符之类的格式。(记住减去 1,为终止 留出空间\'\\0\'
。也就是说,您可以用来%19s
读入char str[20];
or char *p = malloc(20);
。)
这些规则有点多。有关更简单的规则集,请参阅此答案。将规则 7、8、9、12 和 13 放在一起,实际上只有五个完整的格式字符串可以与scanf
: "%d"
, "%s"
, "%f"
, "%lf"
, 或 一起使用" %c"
。(但是没有逗号,没有固定字符串,除了 中的显式空格之外没有空格" %c"
,没有别的。) 例外:如上所述,可以使用类似的东西%19s
来限制正在读取的字符串的长度。
如果您需要做一些在遵守这些规则的情况下无法完成的更复杂的事情,那么是时候执行以下任一操作:
\nscanf
真正起作用(以及不起作用),以便您可以尝试做您想做的事情,但不会陷入这 17 个问题之一,或者scanf
进行输入,也许可以通过使用读取整行fgets
然后解析它们。