如何在C中刷新输入流?

如何在C中刷新输入流?,c,io,stream,stdio,C,Io,Stream,Stdio,我不能在这里冲洗stdin,有办法冲洗吗?如果没有,那么如何使getchar()接受用户输入的字符,而不是输入缓冲区中scanf()留下的“\n” #include "stdio.h" #include "stdlib.h" int main(int argc,char*argv[]) { FILE *fp; char another='y'; struct emp { char name[40]; int age; fl

我不能在这里冲洗stdin,有办法冲洗吗?如果没有,那么如何使
getchar()
接受用户输入的字符,而不是输入缓冲区中
scanf()
留下的“\n”

#include "stdio.h"
#include "stdlib.h"

int main(int argc,char*argv[]) {
    FILE *fp;
    char another='y';
    struct emp {
        char name[40];
        int age;
        float bs;
    };
    struct emp e;
    if(argc!=2) {
        printf("please write 1 target file name\n");
    }
    fp=fopen(argv[1],"wb");
    if(fp==NULL) {
        puts("cannot open file");
        exit(1);
    }
    while(another=='y') {
        printf("\nEnter name,age and basic salary");
        scanf("%s %d %f",e.name,&e.age,&e.bs);
        fwrite(&e,sizeof(e),1,fp);

        printf("Add another record (Y/N)");
        fflush(stdin);
        another=getchar();
    }
    fclose(fp);
    return 0;
}
编辑:已更新代码,仍然无法正常工作

#include "stdio.h"
#include "stdlib.h"

int main(int argc,char*argv[]) {
    FILE *fp;
    char another='y';
    struct emp {
        char name[40];
        int age;
        float bs;
    };
    struct emp e;
    unsigned int const BUF_SIZE = 1024;
    char buf[BUF_SIZE];

    if(argc!=2) {
        printf("please write 1 target file name\n");
    }
    fp=fopen(argv[1],"wb");
    if(fp==NULL) {
        puts("cannot open file");
        exit(1);
    }
    while(another=='y') {
        printf("\nEnter name,age and basic salary : ");
        fgets(buf, BUF_SIZE, stdin);
        sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
        fwrite(&e,sizeof(e),1,fp);
        printf("Add another record (Y/N)");
        another=getchar();
    }
    fclose(fp);
    return 0;
}
输出:

dev@dev-laptop:~/Documents/c++_prac/google_int_prac$ ./a.out emp.dat

Enter name,age and basic salary : deovrat 45 23
Add another record (Y/N)y

Enter name,age and basic salary : Add another record (Y/N)y

Enter name,age and basic salary : Add another record (Y/N)
fflush(stdin)
是未定义的行为(a)。相反,让
scanf
“吃”换行符:

scanf("%s %d %f\n", e.name, &e.age, &e.bs);
其他人都认为
scanf
不是一个好选择。相反,您应该使用
fgets
sscanf

const unsigned int BUF_SIZE = 1024;
char buf[BUF_SIZE];
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);

(a) 例如,请参见
C117.21.5.2 fflush函数

int-fflush(FILE*stream)
-如果流指向未输入最新操作的输出流或更新流,则fflush函数会导致将该流的任何未写入数据发送到主机环境,并写入该文件否则,行为未定义。


使用fflush(stdin)不是一个好的实践,因为它有未定义的行为。通常,像scanf()这样的函数在stdin中留下尾随的换行符。因此,最好使用比scanf()更“干净”的函数。您可以将scanf()替换为fgets()和sscanf()的组合,也可以取消fflush(stdin)。

更新:您需要在循环末尾添加另一个getchar(),以使用Y/n后面的“\n”。我认为这不是最好的方法,但它可以让您的代码按现在的方式工作

while(another=='y') {
    printf("\nEnter name,age and basic salary : ");
    fgets(buf, BUF_SIZE, stdin);
    sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
    fwrite(&e,sizeof(e),1,fp);
    printf("Add another record (Y/N)");
    another=getchar();
    getchar();
}

我建议您将要解析的数据(包括“\n”)读入缓冲区,然后使用sscanf()解析出来。通过这种方式,您可以使用换行符,并且可以对数据执行其他健全性检查。

使用此选项而不是getchar():


我会推荐很多其他人建议的
fgets()
+
sscanf()
方法。您也可以使用
scanf(“%*c”)getchar()
之前的code>。这基本上会吃掉一个字符。

如果在windows下执行此操作,可以在getch()之前使用winapi刷新输入缓冲区

#包括
hStdin=GetStdHandle(标准输入句柄);
冲洗控制台输入缓冲区(hStdin);
-或-

#包括
FlushConsoleInputBuffer(GetStdHandle(标准输入句柄));
  • 正如其他人已经指出的,您不应该将结构写入文件。相反,尝试以格式化的方式写入数据。这样,可以通过查找最后一个和倒数第二个分隔符(例如分号)逐行解析文本文件。请记住,字符串化浮点字段中可能会出现某些字符,如
    '-'
    '.

    int write_data(FILE *fh, struct emp *e) {
        if(fh == NULL || e == NULL)
            return -1;
        fprintf(fh, "%s;%d;%f", e->name, e->age, e->bs);
        return 0;
    }
    
  • 另一件事是,每个人都不断推荐相同的scanf函数族,但没有人检查返回值是否等于要读取的字段数。我认为这是个坏主意,实际上是自找麻烦。即使使用
    strtol
    /
    strtod
    方式,您也需要进行错误检查:

    int parse_int(char *buf, long *result) {
        if(buf == NULL || result == NULL)
            return -1;
        errno = 0;
        *result = strtoul(buf, NULL, 0);
        if(errno != 0) {
            perror("strtoul");
            return -1;
        }
        return 0;
    }
    
  • 上面的两个代码示例以静默方式返回,如果您计划一直使用现有对象调用它们,这是很好的;考虑打印错误消息,并在文档中说明人们在使用函数时应该检查返回值。


    • 标准数据不是可冲洗的,您只能冲洗输出流。也就是说,您根本不需要在stdin上调用flush。

      我尝试过放置\n。但是,即使在为第一条记录输入姓名、年龄、工资后,也不会显示为下一条记录输入Y或n的提示消息。添加“\n”将导致scanf读取,直到遇到文件结尾(在*nix中使用Control+D或在Windows中使用Control+Z)。我已经发布了更新的代码,即使在合并了sscanf和fgets之后,它也不起作用。Andrew在标准中添加了一条引文,希望你不要介意-这总是一个安抚语言律师的好主意。像我一样:-)此外,对于定义了它的操作系统,它可能有进一步的限制,例如,在Linux上,
      fflush
      仅在可查找的流上有效。如果文件被重定向为输入(例如,
      /prog printf(“\n输入姓名、年龄和基本工资”);char szTempBuf[1024];fgets(szTempBuf,1024,stdin);sscanf(szTempBuf,“%s%d%f”,e.name,&e.age,&e.bs)@swatkat,请看一看,向文件写入
      struct
      是不可移植的。@Andrew,这取决于您对可移植性的定义。我想您的意思是,在这种情况下,无法保证在以不同方式填充结构的实现上成功读取结构。您在这方面是正确的。但是,可移植性可以ean其他事情,如“将在所有实现上工作”。根据标准,将结构写入文件是完全可移植的,所有符合标准的实现都应该能够做到这一点,如果它们不做改变填充的事情(例如,使用
      #pragma pack
      )。也许这会更好地表述为:仅供参考,
      struct
      中可能包含填充,如果您尝试在另一个实现中,甚至在同一个实现中使用不同的填充选项来读取它,则可能会导致问题。可能重复的注意事项是,您必须替换“
      unsigned int const BUF_SIZE=1024;
      ”使用“
      #define BUF_SIZE 1024
      ”在C中实现此功能。fflush()用于标准I/O流-什么意思?您不将其用于输入文件-它旨在刷新缓冲输出。但这不是您所说的。使用fflush(stdout)是很好的,甚至是明智的;尤其是在调试模式下。(使用fflush(0)可能更为合理,但这又是一个稍微不同的问题。)谢谢,
      scanf(“%*c”);
      为我在Windows上尝试学习的教程提供了一种享受。但是
      #include <windows.h>
      FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
      
      int write_data(FILE *fh, struct emp *e) {
          if(fh == NULL || e == NULL)
              return -1;
          fprintf(fh, "%s;%d;%f", e->name, e->age, e->bs);
          return 0;
      }
      
      int parse_int(char *buf, long *result) {
          if(buf == NULL || result == NULL)
              return -1;
          errno = 0;
          *result = strtoul(buf, NULL, 0);
          if(errno != 0) {
              perror("strtoul");
              return -1;
          }
          return 0;
      }