C - fgets() 在 fscanf() 之后不起作用



我正在使用fscanf读取日期,然后使用fgets读取注释。但是,在第一次迭代之后,fscanf 返回值 -1。

我使用 GDB 逐步调试程序。在第一次使用 fget 之前,它工作正常。当我尝试打印出第一次迭代时 fgets 读取的行时,它给了我这个:

(gdb) print line
$6 = "rtestr18/04/2010rtest2r03/05/2010rtest3r05/08/2009rtest4rn00000000q352261a370366377267.N=3660000000003000000370xC00000000000000000001000000227b000070367377267H36437726736220204bdoD0035420104b01000000304oC00p363377277260zC00D363377277n!B006436337727735420104b(363377277TzC000000000070367377267010000000000000001000000370xC00010000000000312000000000037726036000010000002770000003643170000344261\0000000000p363377277|23304b350362377277 20404b05000000|23304b30363377277"

看起来 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 时看到的字符串实际上以第一个空字符结尾:

"rtestr18/04/2010rtest2r03/05/2010rtest3r05/08/2009rtest4rn00"

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

最新更新