如何在C中刷新输入流?
我不能在这里冲洗stdin,有办法冲洗吗?如果没有,那么如何使如何在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
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;
}