2

fscanf を使用して日付を読み取り、次に fgets を使用してメモを読み取ります。ただし、最初の繰り返しの後、fscanf は値 -1 を返します。

GDB を使用して、プログラムを段階的にデバッグしました。fgets を最初に使用するまでは問題なく動作します。最初の反復で fgets によって読み取られた行を印刷しようとすると、次のようになります。

(gdb) print line
$6 = "\rtest\r18/04/2010\rtest2\r03/05/2010\rtest3\r05/08/2009\rtest4\r\n\000\000\000\000q\352\261\a\370\366\377\267.N=\366\000\000\000\000\003\000\000\000\370xC\000\000\000\000\000\000\000\000\000\001\000\000\000\227\b\000\000\070\367\377\267H\364\377\267\362\202\004\bdoD\000\354\201\004\b\001\000\000\000\304oC\000p\363\377\277\260zC\000D\363\377\277\n!B\000\064\363\377\277\354\201\004\b(\363\377\277TzC\000\000\000\000\000\070\367\377\267\001\000\000\000\000\000\000\000\001\000\000\000\370xC\000\001\000\000\000\000\000\312\000\000\000\000\000\377\260\360\000\001\000\000\000\277\000\000\000\364\317\000\000\344\261\\\000\000\000\000\000p\363\377\277|\233\004\b\350\362\377\277 \204\004\b\005\000\000\000|\233\004\b\030\363\377\277"

fgets が残りのエントリを読み取り、それらすべてを 1 つの文字列に格納しているように見えます。

なぜこれを行っているのかわかりません。

メインコードは次のとおりです。

int main(int argc, char* argv[]) {
    FILE* file;
    int numEntries, i = 0;
    int index = atoi(argv[1]);
    char line[SIZE];
    JournalEntry *entry;

    /*argument provided is the entry user wants to be displayed*/
    if (argc > 2) {
        perror("Error: Too many arguments provided");
    }
    file = fopen("journalentries.txt", "r");
    if (file == NULL) {
        perror("Error in opening file");
    }

    if (fscanf(file, "%d", &numEntries) != 1) {
        perror("Unable to read number of entries");
    }

    entry = (JournalEntry*)malloc(numEntries  * sizeof(JournalEntry));
    if (entry == NULL) {
        perror("Malloc failed");
    }

    for (i = 0; i < numEntries; i++) {
        if (fscanf(file, "%d/%d/%d", &entry[i].day, &entry[i].month, &entry[i].year) != 3) {
            perror("Unable to read date of entry");
        }

        if (fgets(line, sizeof(line), file) == NULL) {
            perror("Unable to read text of entry");
        }
    }

    printf("%d-%02d-%02d %s: ", entry[index].year, entry[index].month, entry[index].day, entry[index].text);

    if(ferror(file)) {
        perror("Error with file");
    }

    fclose(file);
    free(entry);

    return 0;
}

読む必要があるファイル: 最初の行には、読み取るエントリの数が含まれています

4
12/04/2010
test
18/04/2010
test2
03/05/2010
test3
05/08/2009
test4

ヘッダー ファイルにある構造体 JournalEntry:

typedef struct {
    int day;
    int month;
    int year;
    char text[250];
} JournalEntry;
4

3 に答える 3

1

fgets が残りのエントリを読み取り、それらすべてを 1 つの文字列に格納しているようです。

はい、'\r'行末記号ではありません。したがってfscanf、最初の無効な文字で解析を停止し、それらをバッファに残してからfgets、行の終わりまでそれらを読み取ります。ファイルには有効な行末記号がないため、ファイルの終わりまでです。

おそらく、有効な (Unix?) 行末を持つようにファイルを修正する必要があります。たとえば、それを実行できる適切なテキスト エディタを使用します。しかし、それは以前に尋ねられた別の質問であり(ここのように)、質問に含まれていない詳細に依存します。

fscanfさらに、戻り値の二重チェックが必要です。perror戻り値が -1 の場合にのみ使用してください。それ以外の場合、エラー メッセージはエラーにまったく関連しません。戻り値が>=0必要なものと異なる場合は、カスタムエラーメッセージ「無効な入力構文」などを出力します(そしてfgets、行の残りをバッファから読み取るために使用する可能性があります)。

scanfまた、とを確実に混在fgetsさせるには、フォーマット文字列にスペースを追加する必要があるfscanfため、行末の空白が読み取られます (次の行の先頭と空の行にもあるため、それが重要な場合は注意してください)。 )、 このような:

int items_read = scanf("%d ", &intvalue);

別の回答で述べたように、行fgetsのみを読み取ってから、行ごとに解析するのがおそらく最善sscanfです。

于 2013-10-14T15:47:19.740 に答える