Fgets () does not work after fscanf ()

I use fscanf to read in a date, and then fgets to read a note. However, after the first iteration, fscanf returns -1. A.

I used GDB to debug the program step by step. It works great until the first use of fgets. When I try to print the line read by fgets in the first iteration, it gives me the following:

(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" 

It seems that fgets reads the rest of the records, and then saves them all on the same line.

I'm not sure why he does it.

Here is the main code:

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

File I must read: The very first line contains the number of records to read

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

JournalEntry structure located in the header file:

 typedef struct { int day; int month; int year; char text[250]; } JournalEntry; 
+2
source share
3 answers

It seems that fgets reads the rest of the records, and then saves them all on the same line.

Yes, '\r' not a line terminator. Therefore, when fscanf stops parsing the first invalid character and leaves them in the buffer, then fgets will read them to the end of the line. And since the file does not have valid line terminators, that is, until the end of the file.

You should probably fix the file to have the final lines (Unix?), For example, with a suitable text editor that can do this. But this is another question that was asked earlier (for example, here ) and depends on the details not included in your question.

In addition, you need a double check for the fscanf return value. Use perror only if the return value is -1, otherwise the error message will not be associated with the error at all. If the return value is >=0 , but different from what you need, then print your own error message "invalid input syntax" or whatever (and maybe use fgets to read the rest of the line from the buffer).

Also, in order to reliably mix scanf and fgets , I need to add a space to the fscanf format fscanf so that it reads any spaces at the end of the line (also at the beginning of the next line and any empty lines, so be careful if that matters), for example:

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

As pointed out in another answer, it is best to read lines only with fgets , and then split them into sscanf in turn.

+1
source

Do not mix fscanf() and fgets() as the former may leave material in the stream buffer.

For a linearly-oriented format, read only full lines using fgets() , then use for example. sscanf() to analyze what you read.

+1
source

The line that you see when starting GDB really ends with the first null character:

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

Other data after is ignored (when using ordinary str-functions);

0
source

All Articles