5

ここでstdinをフラッシュできませんが、フラッシュする方法はありますか?そうでない場合は、入力バッファにgetchar()残された「\ n」の代わりに、ユーザーからの入力として文字を取得する方法を教えてください。scanf()

#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)
4

8 に答える 8

10

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)-ストリームが最新の操作が入力されていない出力ストリームまたは更新ストリームを指している場合、fflush関数により、そのストリームの未書き込みデータがホスト環境に配信され、ファイルに書き込まれます。それ以外の場合、動作は定義されていません。

于 2009-09-05T19:30:38.253 に答える
8

更新:Y /Nに続く'\n'を使用するには、ループの最後に別のgetchar()を追加する必要があります。これが最善の方法ではないと思いますが、コードを現在の状態で機能させることができます。

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()を使用して解析することをお勧めします。このようにして、改行を消費し、データに対して他の健全性チェックを実行できます。

于 2009-09-05T19:35:32.760 に答える
3

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 );
    }
于 2009-09-05T20:42:20.060 に答える
2

fflush(stdin)は未定義の動作をするため、使用することはお勧めできません。一般に、scanf()のような関数は、stdinに末尾の改行を残します。したがって、scanf()よりも「クリーン」な関数を使用することをお勧めします。scanf()をfgets()とsscanf()の組み合わせに置き換えることができ、fflush(stdin)を廃止することができます。

于 2009-09-05T19:32:05.187 に答える
2

他の多くの人が提案しているfgets()+アプローチをお勧めします。を呼び出す前にsscanf()使用することもできます。それは本質的にキャラクターを食べるでしょう。scanf("%*c");getchar()

于 2009-09-06T01:08:28.153 に答える
1

Windowsでこれを行う場合は、winapiを使用してgetch()の前に入力バッファをフラッシュできます。

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

-また-

#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
于 2017-11-16T13:07:05.090 に答える
1
  • 他の人がすでに指摘しているように、ファイルに構造体を書くべきではありません。代わりに、フォーマットされた方法でデータを書き込んでみてください。このようにして、セミコロンなどの最後から2番目の区切り文字を見つけることにより、テキストファイルを行ごとに解析できます。文字列化された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;
    }
    
  • もう1つは、誰もが同じ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;
    }
    
  • 上記の2つのコード例はサイレントに返されます。これは、既存のオブジェクトを常に使用して呼び出す場合は問題ありません。ただし、エラーメッセージを出力することを検討し、ドキュメントで、関数を使用するときに戻り値を確認する必要があることを示してください。

于 2017-12-02T08:43:07.500 に答える
0

stdinはフラッシュ可能なものではなく、出力ストリームのみをフラッシュできます。つまり、stdinでflushを呼び出す必要はまったくありません。

于 2018-10-30T11:13:00.717 に答える