【问题标题】:Why should I use fflush(stdin) in this program?为什么我应该在这个程序中使用 fflush(stdin)?
【发布时间】:2015-07-12 22:47:31
【问题描述】:

我知道它是用来清理键盘缓冲区的,但 我不明白何时/为什么需要使用它,或者我是否真的需要。

例如,在我为我的班级编写的这段代码中,它只有在我将fflush(stdin) 放在while 之后的主函数中才有效,我只知道这一点,因为教授告诉我这样做之后我已经向他展示了错误。

问题是否与 struct 相关,这就是为什么我应该使用 fflush(stdin)

代码如下:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

struct CLIENTES
{
    int ano_nasc, cpf[11];
    float renda_m;
    char nome[50];
}; //Lista de Objetos

int main(void) 
{
    //Declaracao de Variaveis
    int cont=0, num, num_2, client, i, j;
    CLIENTES *vet;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    scanf("%d%*c", &num);
    vet = (CLIENTES*)malloc(num*sizeof(*vet));
    printf("Digite os Dados do Cliente.");

    while (cont != num)
    {  
        fflush(stdin);
        printf("\nNome: ");
        fgets(vet[cont].nome, sizeof(vet[cont].nome), stdin);
        printf("\nAno de Nascimento: ");
        scanf("%d", &vet[cont].ano_nasc);
        printf("\nCPF: ");
        scanf("%d", &vet[cont].cpf);
        printf("\nRenda Mensal: ");
        scanf("%f", &vet[cont].renda_m);
        cont++;
    }

    printf("\nDigite o numero do cliente que voce deseja conferir: ");
    scanf("%d", &num_2);
    for (i=0;i<num;i++)
    {
        if(num_2 == num)
        {
            printf("\nO que deseja saber sobre ele?\n");
            printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
            scanf("%d", &client);
            if (client == 1)
            {
                printf("Nome: %s", vet[(num_2)-1].nome );
            }
            else if(client == 2)
            {
                printf("Ano de Nascimento: %d", vet[num_2].ano_nasc );
            }
            else if(client == 3)
            {
                for(j=0;j<11;j++)
                {
                    printf("CPF: %d", vet[num_2].cpf[j]);
                }
            }
            else if(client == 4)
            {
                printf("Renda Mensal: %f", vet[num_2].renda_m );
            } 
        }
    }

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    getch();
    return 0;
} 

【问题讨论】:

  • 在标准 C 库中执行 fflush(stdin) 是非法的。行为未定义。
  • @AnT omg,我真的不知道,你能解释一下这个概念吗?
  • @AnT:它确实有未定义的行为,但并不违法。行为是defined by POSIX。不过,在这里使用它可能不是一个好主意。您希望在读取和丢弃一些数据的意义上刷新输入。
  • 查看Using fflush(stdin) 了解它的作用。由于您使用的是&lt;conio.h&gt;,因此您可能在 Windows 上工作,fflush(stdin) 的行为由 Mi​​corsoft 定义。
  • @JonathanLeffler 感谢您的建议和解释。

标签: c struct


【解决方案1】:

如果说标准 C,实际上教授是错误的。根据标准,在输入流(例如stdin)上调用fflush是未定义的行为。

但是,在许多实现中(包括 Linux†、OS X、各种 BSD 等)fflush(stdin) 会丢弃任何已缓冲但尚未使用的输入。在您的程序中使用此非标准功能来清除输入缓冲区中由前一个 scanf 留下的尾随换行符。

Linux 上的man fflush 非常友好地提到这是非标准的(尽管措辞并不完全暗示未定义的行为):

标准没有指定输入流的行为。

同时C11标准下7.21.5.2的fflush函数说:

如果stream 指向未输入最新操作的输出流或更新流,fflush 函数会导致该流的任何未写入数据被传递到主机环境以写入文件;否则,行为未定义。

† 根据 cmets 的说法,尽管 man fflush 声称应该这样做,但这种非标准行为可能无法在 Linux 上运行。

【讨论】:

  • 这很有趣!所以在这个程序中使用 fflush(stdin) 的建议是不正确的,但是清理 scanf 的输入缓冲区效果很好,对吧?我应该使用其他东西而不是 fflush(stdin) 吗?谢谢。
  • @gm_fernandes fflush(stdin) 如果您接受该程序不再是标准 C 就可以了。您可以实现自己的函数来“刷新”缓冲区,例如,逐个字符地使用,直到您遇到某些问题除了空格,然后是ungetc 最后一个字符。或者您可以完全重新考虑输入 - 将fgets 输入到缓冲区中,而来自该缓冲区的sscanf 通常比使用scanf 更可取,在这里您甚至可以使用strtodstrtol 而不是sscanf .
  • 我真的很喜欢你的回答,它在理解我的代码内部以及这个函数如何工作方面帮助了我很多。谢谢你!
  • 虽然fflush(stdin) 在 Linux 上不会崩溃或发生任何事情,但它也不会像在 DOS/Windows 上那样清除输入...
  • @Dmitri Interesting – on Debian jessie man fflush 声称 fflushing 输入流会丢弃缓冲但未使用的数据。
【解决方案2】:
  1. 不应在 C 程序中使用 fflush(stdin)。它没有很好的定义。它不便携。

  2. 您不应该需要在 C 程序中使用 fflush(stdin)。遗憾的是,唯一出现这种需求的情况是,当程序员正在学习 C 并大量使用 scanf 并且遇到 scanf 的一个臭名昭著的困难之一时。简单地说,停止使用scanf,刷新输入的“需要”就消失了。或者,插入对getchar 的额外调用,或循环读取并丢弃输入直到换行符,如其他地方所述。

【讨论】:

    猜你喜欢
    • 2014-05-19
    • 2012-12-27
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 2021-09-17
    • 2018-06-16
    • 1970-01-01
    • 2014-03-24
    相关资源
    最近更新 更多