fgets()在fscanf()之后无法正常工作

我使用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读取剩余的条目,然后将它们全部存储在一个字符串中。

我不确定为什么会这样做。

这是主要代码:

 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; 

它看起来像fgets读取剩余的条目,然后将它们全部存储在一个字符串中。

是的, '\r'不是行终止符。 因此,当fscanf停止解析第一个无效字符并将它们留在缓冲区中时, fgets将读取它们直到行结束。 并且由于文件中没有有效的行终止符,因此直到文件结束。

您应该修复该文件以获得有效的(Unix?)行结尾,例如使用合适的文本编辑器即可。 但这是另一个问题,之前已经被问过(比如这里 ),并且取决于你问题中没有包含的细节。

此外,您需要双重检查fscanf返回值。 仅当返回值为-1时才使用perror ,否则错误消息将根本不与错误相关。 如果返回值>=0但与您想要的不同,则打印自定义错误消息“无效输入语法”或其他任何内容(并且可能使用fgets从缓冲区中读取其余行)。

另外,为了可靠地混合scanffgets ,我需要在fscanf格式字符串中添加空格,因此它将读取行尾的任何空格(也在下一行的开头和任何空行,所以要小心如果这很重要),像这样:

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

正如另一个答案中所述,最好只读取带有fgets行,然后逐行解析sscanf

不要混用fscanf()fgets() ,因为前者可能会在流的缓冲区中留下东西。

对于面向行的格式,使用fgets()只读取整行,然后使用例如sscanf()来解析您所读取的内容。

运行GDB时看到的字符串确实以第一个空字符结束:

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

忽略其他数据(使用普通的str函数时);