读取数字和换行符时出现奇怪的scanf行为
我只是在用C做了8年后才意识到scanf的’bug’。
scanf代码下方将跳过第二行输入中的前导空白字符。
int x; char in[100]; scanf("%d\n",&x); gets(in);
输入:
1 s
x
将包含1
,但是只是"s"
而不是" s"
这个标准C还是gcc行为?
scanf
格式字符串中的空格字符将导致scanf
消耗任何(和所有)空白区域,直到出现非空白字符。
这似乎是标准的scanf
行为,并不仅限于gcc。
它不是scanf
的Bug, scanf
的手册说,
一系列空格字符(空格,制表符,换行符等;请参阅
isspace(3)
)。 该指令匹配输入中的任何数量的空白区域,包括无空格。
这意味着任何带有指令%d\n
空白字符将读取一个数字,然后在输入中使用一系列空白字符,并且只有在您键入非空白字符时才会返回。 那你怎么能只看到没有空格的"s"
。
'\n'
(对于格式字符串中的任何空格字符都是如此)
scanf("%d\n", &x);
匹配输入中的任意数量的空白字符( isspace
函数返回1的字符,即true,如换行符,空格,制表符等),而不仅仅是换行符'\n'
。 这意味着scanf
将读取输入中的所有空白字符并将其丢弃,直到遇到非空白字符。 这解释了您观察到的行为。
这是scanf
函数的标准定义的一部分,而不是gcc
function。 此外, gets
function已被弃用 且不安全 。 它不会检查缓冲区溢出,并可能导致错误甚至程序崩溃。 事实上, gcc
发出警告,反对在我的机器上使用gets
。 建议使用fgets
。
要做你想做的事,你可以做以下事情:
int x; char in[100]; scanf("%d", &x);
在scanf
成功返回后,输入流可以包含由换行符终止的任何字符序列,具体取决于用户给出的输入。 在从stdin读取字符串之前去除那些无关的字符。
char ch; while((ch = getchar()) != '\n' || ch != EOF); // null statement fgets(in, 100, stdin);
上面的fgets
调用意味着它将最多读取100-1 = 99
(它为终止空字节保存一个字符空间,它将在退出之前添加到正在读取的缓冲区中)来自stdin
指向的流中的字符并存储它们在缓冲区中指向的。 如果遇到EOF
, '\n'
或者它已经读取了100-1个字符,则fgets
将退出 – 这三个条件中的任何一个首先出现。 如果它读取换行符,它会将其存储到缓冲区中。
在这种情况下,用户是否输入100个字符或更多字符,那么无关的字符将位于输入缓冲区中,这可能会影响scanf
, fgets
, getchar
等调用后续字符或字符串的输入操作。 您可以检查此字符串的长度。
if(strlen(in) > 99) { // extraneous chars lying around in the input buffer // read and discard them char ch; while((ch = getchar()) != '\n' || ch != EOF); // null statement }