这两个scanf语句有什么区别?

时间:2016-01-12 09:29:50

标签: c newline scanf format-specifiers

我有一些疑问。怀疑是

以下两个scanf语句之间有什么区别。

scanf("%s",buf);

scanf("%[^\n]", buf);

如果我在while循环中给出第二个scanf,它将无限进行。因为\n位于stdin

但是在第一个声明中,读到\n之前。它也不会读取\n

但是第一个声明不是无限的。为什么?

7 个答案:

答案 0 :(得分:2)

关于%s格式说明符的属性,引用C11 standrad,章节§7.21.6.2,fscanf()

  

s匹配一系列非空白字符。

换行符是空白字符,因此只有newlinew不匹配%s

因此,如果换行符保留在缓冲区中,它不会单独扫描换行符,并等待下一个非空格输入显示在stdin上。

答案 1 :(得分:1)

%s格式说明符指定scanf()应该读取标准输入缓冲区stdin中的所有字符,直到它遇到第一个空白字符,然后停在那里。空格('\n')保留在stdin缓冲区中,直到被getchar()等其他函数使用。

在第二种情况下,没有提到停止。

答案 2 :(得分:1)

您可以将scanf视为从字符流中提取由空格分隔的单词。例如,想象一下,读取包含数字表的文件,而不必担心每行的确切数量或确切的空间数和数字之间的性质。

对于记录,空白是水平和垂直(这些存在的)制表符,回车符,换行符,换页符,最后是实际空格。

为了使用户免于细节,scanf将所有空格都视为相同:它通常跳过它直到它到达非空格,然后根据指定的输入转换尝试转换从那里开始的字符序列。例如。对于“%d”,它需要一个数字序列,可能前面带有减号。

输入转换“%s”也从跳过空格开始(opengroup's man page中记录的内容比Linux one中更清晰)。

在跳过前导空格后,“%s”接受所有内容,直到读取另一个空格(并将其放回输入中,因为它不是被读取的“单词”的一部分)。这个非空白字符序列 - 基本上是一个“字” - 存储在提供的缓冲区中。例如,从" a bc "扫描字符串会导致跳过3个空格并在缓冲区中存储“a”。 (下一个scanf将跳过中间空格并将“bc”放入缓冲区。之后的下一个scanf将跳过剩余的空格,遇到文件结尾并返回EOF。)因此,如果要求用户输入三个单词,可以在一行或三行或任意数量的行上给出三个单词,前面或任意数量的空行分隔,即任意数量的后续换行。 Scanf不在乎。

“跳过领先的空白”策略有一些例外。两者都涉及转换,这些转换通常表明用户希望对输入转换有更多控制权。其中一个是“%c”,它只读取下一个字符。另一个是“%[”规范,它详细说明了哪些字符被认为是要读取的下一个“字”的一部分。您使用的转换规范“%[^ \ n]”会读取除换行符之外的所有。来自键盘的输入通常逐行传递给程序,并且每行按定义以换行符终止。传递给程序的第一行的换行符将是输入流中与转换规范不匹配的第一个字符。 Scanf将读取它,检查它,然后将其放回输入流(带ungetc())以供其他人使用。不幸的是,它本身就是下一个消费者,在另一个循环迭代中(我假设)。现在它遇到的第一个字符(换行符)与输入转换不匹配(它需要任何换行符)。因此,Scanf立即放弃,将有问题的字符尽职尽责地放回输入中供其他人使用,并返回0表示甚至无法在格式字符串中进行第一次转换。但唉,它本身将成为下一个消费者。是的,机器是愚蠢的。

答案 3 :(得分:0)

首先 scanf(“%s”,buf); 仅扫描字或字符串,但第二次 scanf(“%[^ \ n]”,buf); 读取字符串,直到用户输入为新行字符。

答案 4 :(得分:0)

您可以将%s视为%[^\n \t\f\r\v],也就是说,在跳过任何前导空格后,将一组视为非空白字符。

答案 5 :(得分:0)

让我们来看看这两个代码段:

#include <stdio.h>

int main(void){

        char sentence[20] = {'\0'};

        scanf("%s", sentence);

        printf("\n%s\n", sentence);

return 0;

}

输入:您好,我的名字是Claudio。

输出:你好

#include <stdio.h>

int main(void){

        char sentence[20] = {'\0'};

        scanf("%[^\n]", sentence);

        printf("\n%s\n", sentence);

return 0;

}

输入:您好,我的名字是Claudio。

输出:您好,我的名字是Claudio。

%[^\n]是一个反向组扫描,这是我个人使用它的方式,因为它允许我输入带有空格的sentece。

答案 6 :(得分:0)

<强>公用

两者都希望buf成为指向字符数组的指针。如果保存了至少1个字符,则都会向该数组附加空字符。如果保存了某些内容,则返回1。如果在保存任何内容之前检测到文件结尾,则返回EOF。检测到输入错误中的返回EOF。两者都可以保存buf,其中包含嵌入的'\0'个字符。

scanf("%s",buf);
scanf("%[^\n]", buf);

<强>差异

"%s" 1)消耗并丢弃包含'\n',空格,制表符等的前导空格.2)然后将非空白空间保存到buf直到3)白色检测到空格(然后将其放回stdin)。 buf不会包含任何空格。

"%[^\n]" 1)消耗并丢弃领先的空白区域。 2)它将非'\n'个字符保存到buf,直到3)检测到'\n'(然后将其放回stdin)。如果读取的第一个字符是'\n',则buf没有保存,并返回0。 '\n'保留在stdin中并解释了OP的无限循环。

未能测试scanf()的返回值是一种常见的代码疏忽。更好的代码检查scanf()的返回值。

IMO:代码永远不应该使用:

两者都无法限制读取的字符数。使用fgets()