为什么我们需要在%c之前放置空间?

8 c character

下面的代码在我编译它时会给出奇怪的o/p.

main() {
    char name[3];
    float price[3];
    int pages[3], i;

    printf ( "\nEnter names, prices and no. of pages of 3 books\n" ) ;

    for ( i = 0 ; i <= 2 ; i++ )
        scanf ("%c %f %d", &name[i], &price[i], &pages[i] );

    printf ( "\nAnd this is what you entered\n" ) ;

    for ( i = 0 ; i <= 2 ; i++ )
        printf ( "%c %f %d\n", name[i], price[i], pages[i] );
}
Run Code Online (Sandbox Code Playgroud)

但是如果我们在%c之前给scanf语句中的空格,它给出了正确的o/p.

任何人都可以解释我为什么会这样?

更新: -

如果我提供这样的输入 -

F
123.45
56
J
134
67
K
145
98
Run Code Online (Sandbox Code Playgroud)

那么我的问题是为什么我们不在%d之前给%f和空格前空间?为什么我们只需要在%c之前提供空间?

lus*_*oog 14

将空格添加到格式字符串可以scanf使用每次按下时发生的输入中的换行符return.没有空间,name[i]将接收char '\n',真正的 char被留下来被误解%f.

所以,说你的输入是

a 1.0 2
b 3.0 4
c 5.0 6
Run Code Online (Sandbox Code Playgroud)

该程序看起来更像这样:

a 1.0 2\nb 3.0 4\nc 5.0 6\n\377
Run Code Online (Sandbox Code Playgroud)

也就是说,换行符是文件中的实际字符(这里的\ 377表示"文件结束").

第一个scanf似乎工作正常,消耗char,浮点数和整数.但它留下了这样的输入:

\nb 3.0 4\nc 5.0 6\n\377
Run Code Online (Sandbox Code Playgroud)

所以第二个scanf将读取'\n'它的%c,除非你先摆脱它.

将空格添加到格式字符串会指示scanf丢弃任何空白字符(空格' ',制表符'\t'或换行符中的任何一个'\n').

指令是以下之一:

  • 一系列空格字符(空格,制表符,换行符等;请参阅isspace(3)).该指令在输入中匹配任意数量的空白,包括无空格.

  • ...

来自http://linux.die.net/man/3/scanf


无论何时在循环中使用scanf,都会出现这种问题%c.因为,假设自由形式输入,换行可以在任何地方发生.因此,通过使用双层方法来避免整个问题是很常见的.您将输入读入缓冲区(使用fgets); 切断愚蠢的换行符; 然后使用sscanf而不是scanf从缓冲区(字符串)读取而不是直接从文件中读取.

  • 只是添加到luser droog.新行字符将存储在缓冲区中,scanf首先看到缓冲区,如果缓冲区不为空,则从缓冲区获取输入.否则它来自stdin.所以为了刷新缓冲区,我们在scanf中放置了%c的空间. (2认同)

小智 5

使用%c的输入不正确

考虑以下代码片段:

int main( ){
int x;
char y;
scanf("%d", &x);
scanf("%c", &y);
printf("%d %c", x, y);
}
Run Code Online (Sandbox Code Playgroud)

行为:
运行上述程序时,将调用第一个scanf,它将等待您输入十进制数字。假设您输入12(即ASCII'1'和ASCII'2')。然后,您按“输入”键以表示输入结束。接下来,程序将执行第二个scanf,除了您会注意到程序不等待您输入字符,而是直接输出到12后跟一个'\ n'。



说明:
为什么会这样呢?让我们逐步看一下程序的行为。最初,缓冲区中没有任何内容。调用第一个scanf()时,它没有任何要读取的内容,因此将等待。它一直等待,直到您键入1,2,然后“输入”。现在缓冲区中的内容是字符1,字符2和字符'\ n'。请记住,一旦输入所有字段,“ \ n”就表示输入结束,但是它也作为ASCII字符存储在缓冲区中。此时,scanf将从缓冲区读取最大的十进制输入,并将其转换为整数。在此示例中,它将找到字符串“ 12”,并将其转换为十进制值十二,然后将其放入x中。然后scanf将控制权返回给主函数并返回值1,能够成功转换一个条目。在我们的示例中,我们没有在变量中捕获scanf的返回值。对于健壮的代码,检查scanf()的返回值以确保用户输入正确的数据非常重要。



现在缓冲区中剩下的是“ \ n”。接下来,调用第二个scanf,并且它期待一个字符。因为缓冲区中已经有'\ n'字符,所以scanf会看到它,将其从缓冲区中取出,然后放入y中。这就是为什么当您随后执行printf时,屏幕上会打印12和“ enter”的原因。



解决方案:
故事的寓意是,enter是一个与其他字符一样的字符,并输入到缓冲区,并像其他任何ASCII字符一样,由%c从缓冲区中使用。要解决此问题,请尝试使用以下代码:


int main( ){
int x;
char y;
scanf("%d", &x);
scanf("\n%c", &y); /* note the \n !! */
printf("%d %c", x, y);
}
Run Code Online (Sandbox Code Playgroud)

**

这如何解决问题?


**因此,再次输入“ 1”,“ 2”,“ \ n”。第一个scanf读取“ 1”和“ 2”,将其转换为十进制的12,并将'\ n'保留在缓冲区中。现在,下一个scanf期望在下一个输入的开始处有一个'\ n'。它在缓冲区中找到“ \ n”,然后读取并丢弃它。现在缓冲区为空,scanf正在等待用户输入字符。假设用户输入“ c”,然后按Enter键。现在将'c'分配给y,而不是“ enter”。因此,printf将在屏幕上输出“ 12 c”。注意:队列中现在又有一个'\ n'。因此,如果您需要对单个字符进行另一个scanf,则必须先“消耗”该'\ n',然后再从用户那里获取另一个字符。

这对于任何其他格式说明符都不是问题,因为它们都忽略输入之前的空格。