我无法在此处刷新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)
更新:您需要在循环的末尾添加另一个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()解析出来。这样,您可以使用换行符,并且可以对数据执行其他完整性检查。
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)例如,请参见C11 7.21.5.2 The fflush function
:
int fflush(FILE *stream)
-如果stream指向未输入最近操作的输出流或更新流,则fflush函数会使该流的所有未写数据传送到要写入文件的主机环境; 否则,行为是不确定的。
使用它代替getchar():
char another[BUF_SIZE] = "y";
while( 'y' == another[0] )
{
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)" );
fgets( another, BUF_SIZE, stdin );
}
使用fflush(stdin)不是一种好的做法,因为它具有未定义的行为。通常,像scanf()这样的函数在stdin中留下尾随换行符。因此,最好使用比scanf()更“干净”的函数。您可以用fgets()和sscanf()的组合替换scanf(),而不必使用fflush(stdin)。
我会推荐许多其他人建议的fgets()
+ sscanf()
方法。您也可以在调用scanf("%*c");
之前使用getchar()
。从本质上讲,这会吃掉角色。
如果在Windows下执行此操作,则可以使用winapi在getch()之前刷新输入缓冲区。
#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
-或-
#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
正如其他人已经指出的那样,您不应将结构写入文件。而是尝试以格式化的方式写入数据。这样,可以通过查找最后一个和倒数第二个分隔符(例如分号)来逐行分析文本文件。请记住,某些字符,例如'-'
或'.'
,可能会出现在字符串化的float字段中。
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不可刷新,您只能刷新输出流。即您完全不需要在stdin上调用flush。