【问题标题】:three scanf resulting in two and taking garbage value三个 scanf 导致两个并取垃圾值
【发布时间】:2016-03-20 12:12:23
【问题描述】:

这是基本结构的代码,但输出与预期不符。有三个 scanf 函数,但只有两个正在执行。中间一个包含垃圾值。

#include <stdio.h>

int main()
{
    struct book
    {
        char name;
        float price;
        int pages;
    };

    struct book b1,b2,b3;

    printf("Enter names , prices & no of pages of 3 books\n");
    scanf("%c%f%d",&b1.name,&b1.price,&b1.pages);
    scanf("%c%f%d",&b2.name,&b2.price,&b2.pages);
    scanf("%c%f%d",&b3.name,&b3.price,&b3.pages);

    printf("And this is what you entered\n");
    printf("%c%f%d",b1.name,b1.price,b1.pages);
    printf("%c%f%d",b2.name,b2.price,b2.pages);
    printf("%c%f%d",b3.name,b3.price,b3.pages);

    return 0;
}

【问题讨论】:

  • scanf("%c%f%d" --> scanf(" %c%f%d"
  • 由于某些缓冲区规则,例如scanf("%c %d %f", bla, blaa, blaaa);,在数字或浮点数之前提供一些空格
  • 需要查看scanf的返回值:if (scanf("%c%f%d", &amp;b1.name, &amp;b1.price, &amp;b1.pages) != 3) { fprintf(stderr, "Error reading b1 input.\n"); exit(EXIT_FAILURE); }
  • 跳过前一个换行符。
  • @SCaffrey 输入不完整。它将继续等待非空白的输入。

标签: c char scanf


【解决方案1】:

简单的改变

scanf("%c%f%d", &bx.name, &bx.price, &bx.pages);

scanf(" %c%f%d", &b1.name, &b1.price, &b1.pages);

按下 Enter 后,stdin 中会留下一个 '\n',稍后将被 "%c" 使用。读取一个字符('\n')后,scanf() 需要一个浮点数,如格式字符串中的“%f”所示。但是,它没有得到所需的浮点数,而是遇到了一个字符,然后很遗憾地返回。因此,&amp;bx.price&amp;bx.pages 不会更新,因此它们保持未初始化状态,从而为您提供垃圾值。

scanf() 中有一个前导空格,所有空白字符(如果有)在读取开始前都会被丢弃。由于\n 被丢弃,接下来的读取过程将(大概)成功。

另外,只是一个提示:始终检查scanf()的返回值,因为你永远不会知道用户会输入什么。

示例代码:

#include <stdio.h>

struct book
{
    char name;
    float price;
    int pages;
};

int main()
{
    struct book b1, b2, ..., bx;

    printf("Enter names, prices & no of pages of x books:\n");
    while (scanf(" %c%f%d", &bx.name, &bx.price, &bx.pages) != 3)
    { 
        fputs("Error reading bx. Please try again:\n", stderr);
        scanf("%*[^\n] ");
    }
    ......

    printf("And this is what you have entered:\n");
    printf("%c %f %d", bx.name, bx.price, bx.pages);
    ......

    return 0;
}

输入输出示例:

Enter names, prices & no of pages of x books:
asd wedewc efcew
Error reading bx. Please try again:
a 12.34 42
And this is what you have entered:
a 12.340000 42

【讨论】:

    【解决方案2】:

    scanf 通常从标准输入流中读取字符,其中包括换行符和空格。因此,在使用 scanf("%c"); 之前,请尝试刷新 stdin 流中剩余的所有不需要的输入;

    还要记住:不要让 %c 落在格式字符串中间的某个地方

    希望这会有所帮助。不幸的是,您应该在“您的”程序中的所有 scanf 之前使用它

    printf("Enter names , prices & no of pages of 3 books\n");
    fflush(stdin);
    scanf("%c%f%d",&b1.name,&b1.price,&b1.pages);
    

    您也可以在 scanf 中的 %c 之前使用一个空格来读取空格。

    scanf(" %c"....);
    

    【讨论】:

    • fflush(stdin); 不是未定义的行为吗?
    • @sun qingyao 是的fflush(stdin)是UB。 C11 规范:“Ifstream 指向输出流或更新流...... fflush 函数会导致该流的任何未写入数据被传递......否则,行为未定义。”。 stdin 不是输出流或更新流。在 一些 系统上,fflush(stdin) 它会清空流,而其他机器上的相同代码会产生不同的结果。健壮的代码不使用fflush(stdin)