2013-10-14 3 views
2

Я использую fscanf для чтения в дате, а затем fgets, чтобы прочитать примечание. Однако после первой итерации fscanf возвращает значение -1.fgets() не работает после fscanf()

Я использовал 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 читает оставшиеся записи и затем сохраняет их все в одной строке.

Я не уверен, почему он это делает.

Вот основной код:

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 

В STRUCT JournalEntry, расположенный в файл заголовка:

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

Откуда берутся входной файл, используя '\ r' в качестве терминатора линии? Концы строк должны быть '\ n'. – alk

+0

Я создал входной файл с помощью notepad ++ – kaozgamer

+0

@kaozgamer попробуйте с 'numEntries -1' –

ответ

1

Похоже, что fgets читает остальные записи, а затем сохраняет их все в одной строке.

Да, '\r' не является терминатором линии. Поэтому, когда fscanf останавливает синтаксический анализ при первом недопустимом символе и оставляет их в буфере, тогда fgets будет читать их до конца строки. И так как в файле нет допустимых терминаторов строк, то есть до конца файла.

Возможно, вы должны исправить файл, чтобы иметь окончательные строки (Unix?), Например, с подходящим текстовым редактором, который может это сделать. Но это еще один вопрос, который был задан раньше (например, here) и зависит от деталей, не включенных в ваш вопрос.

Кроме того, вам нужна двойная проверка для возвращаемого значения fscanf. Используйте perror, только если возвращаемое значение равно -1, в противном случае сообщение об ошибке вообще не будет связано с этой ошибкой. Если возвращаемое значение равно >=0, но отличается от того, что вы хотели, затем распечатайте собственное сообщение об ошибке «недопустимый синтаксис ввода» или что-то еще (и, возможно, используйте fgets, чтобы прочитать остальную часть строки из буфера).

Кроме того, чтобы надежно смешивать scanf и fgets, я вам необходимо добавить пространство в строке формата fscanf, поэтому он будет читать любой пробел в конце строки (также в начале следующей строки и любые пустые строки , так что будьте осторожны, если это имеет значение), как это:

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

Как сказано в другом ответе, это, вероятно, лучше всего читать строки с fgets только затем разобрать их sscanf линия за линией.

+0

Я воссоздал входной файл в gvim. Добавление пробела в строку формата fscanf привело к трюку. Благодаря! – kaozgamer

1

Не смешивайте fscanf() и fgets(), так как первый может оставить материал в буфере потока.

Для линейного ориентированного формата читайте только полные строки, используя fgets(), затем используйте, например,sscanf(), чтобы разобрать то, что вы прочитали.

0

Строки вы видите при запуске GDB действительно заканчивается в первом нулевом символе:

"\rtest\r18/04/2010\rtest2\r03/05/2010\rtest3\r05/08/2009\rtest4\r\n\000" 

Другие данные после того, как игнорируются (при использовании обычных СИЛ-функция);

Смежные вопросы