如何在 C 中刷新输入流?

发布于 2024-08-04 09:33:15 字数 1984 浏览 7 评论 0原文

我无法在这里刷新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)

I am not able to flush stdin here, is there a way to flush it? If not then how to make getchar() to take a character as input from user, instead of a "\n" left by scanf() in the input buffer??

#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;
}

EDIT: updated code, still not working properly

#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;
}

Output:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

假装不在乎 2024-08-11 09:33:15

fflush(stdin) 是未定义的行为(a)。相反,让 scanf “吃掉”换行符:

scanf("%s %d %f\n", e.name, &e.age, &e.bs);

其他人都认为 scanf 是一个糟糕的选择。相反,您应该使用 fgetssscanf

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 fflush 函数:

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


fflush(stdin) is undefined behaviour(a). Instead, make scanf "eat" the newline:

scanf("%s %d %f\n", e.name, &e.age, &e.bs);

Everyone else makes a good point about scanf being a bad choice. Instead, you should use fgets and 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) See, for example, C11 7.21.5.2 The fflush function:

int fflush(FILE *stream) - If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.

一直在等你来 2024-08-11 09:33:15

更新:您需要在循环末尾添加另一个 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() 解析它。通过这种方式,您可以使用换行符,并且可以对数据执行其他健全性检查。

Update: You need to add another getchar() at the end of your loop to consume the '\n' that follows the Y/N. I don't think this is the best way to go, but it will make your code work as it stands now.

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();
}

I would suggest reading the data you want to parse (up to and including the '\n') into a buffer and then parse it out using sscanf(). This way you consume the newline and you can perform other sanity checks on the data.

青衫负雪 2024-08-11 09:33:15

使用它代替 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 );
    }

Use this instead of 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 );
    }
流星番茄 2024-08-11 09:33:15

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

It's not a good practice to use fflush( stdin ) as it has undefined behavior. Generally, functions like scanf() leaves trailing newlines in stdin. So, it is better to use functions that are "cleaner" than scanf(). You can replace your scanf() with a combination of fgets() and sscanf() and you can do away with fflush( stdin ).

熟人话多 2024-08-11 09:33:15

我会推荐很多其他人建议的 fgets()+sscanf() 方法。您还可以在调用 getchar() 之前使用 scanf("%*c");。这基本上会吃掉一个角色。

I would recommend the fgets()+sscanf() approach that a lot of other people have suggested. You could also use scanf("%*c"); before the call to getchar(). That will essentially eat a character.

笑梦风尘 2024-08-11 09:33:15

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

#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);

-或者-

#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

If you are doing this under windows, you can use winapi to flush input buffer before your getch().

#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);

-or-

#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
时光磨忆 2024-08-11 09:33:15
  • 正如其他人已经指出的那样,您不应该将结构写入文件。相反,尝试以格式化的方式写入数据。这样,您的文本文件就可以通过查找最后一个和倒数第二个分隔符(例如分号)来逐行解析。请记住,字符串化浮点字段中可能会出现某些字符,例如 '-''.'

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

    int parse_int(char *buf, long *result) {
        if(buf == NULL || 结果 == NULL)
            返回-1;
        错误号=0;
        *结果 = strtoul(buf, NULL, 0);
        如果(错误号!= 0){
            错误(“strtoul”);
            返回-1;
        }
        返回0;
    }
    
  • 上面的两个代码示例会默默返回,如果您计划使用现有对象来调用它们,那么这很好。时间;不过,请考虑打印一条错误消息,并在文档中说明人们在使用函数时应该检查返回值。

  • As others already pointed out, you should not write a struct to a file. Instead, try to write the data in a formatted manner. This way your text file can be parsed line-by-line by finding the last and second-to-last delimiters, for example semicolons. Keep in mind that certain characters like '-' or '.' may occur in the stringified float field.

    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;
    }
    
  • The other thing is how everybody keeps recommending the same scanf family of functions, but nobody ever checks whether the return value is equal to the number of fields to be read. I think that is a bad idea, effectively asking for trouble. Even with the strtol/strtod way you need error checking:

    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;
    }
    
  • the two code examples above return silently which is fine if you plan to call them using existing objects all the time; consider printing an error message, though, and illustrate in your documentation that people should check the return values when using your functions.

゛时过境迁 2024-08-11 09:33:15

stdin 不是可刷新的东西,您只能刷新输出流。也就是说,您根本不需要在标准输入上调用刷新。

stdin is not something flushable, you can flush only output streams. I.e. you don't need to call flush on stdin at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文