我正在使用fscanf读取日期,然后使用fgets读取注释。但是,在第一次迭代之后,fscanf 返回值 -1。
我使用 GDB 逐步调试程序。在第一次使用 fget 之前,它工作正常。当我尝试打印出第一次迭代时 fgets 读取的行时,它给了我这个:
(gdb) print line
$6 = "rtestr18/04/2010rtest2r03/05/2010rtest3r05/08/2009rtest4rn 00 00 00 00q352261a370366377267.N=366 00 00 00 00 03 00 00 00370xC 00 00 00 00 00 00 00 00 00 01 00 00 00227b 00 00 70367377267H364377267362202 04bdoD 00354201 04b 01 00 00 00304oC 00p363377277260zC 00D363377277n!B 00 64363377277354201 04b(363377277TzC 00 00 00 00 00 70367377267 01 00 00 00 00 00 00 00 01 00 00 00370xC 00 01 00 00 00 00 00312 00 00 00 00 00377260360 00 01 00 00 00277 00 00 00364317 00 00344261\ 00 00 00 00 00p363377277|233 04b350362377277 204 04b 05 00 00 00|233 04b 30363377277"
看起来 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
从缓冲区中读取行的其余部分)。
另外,为了可靠地混合scanf
和fgets
,我需要在fscanf
格式字符串中添加空格,因此它将读取行尾的任何空格(也在下一行的开头和任何空行,所以如果这很重要,请小心),如下所示:
int items_read = scanf("%d ", &intvalue);
如另一个答案中所述,最好只阅读fgets
行,然后逐行解析sscanf
行。
不要混合fscanf()
和fgets()
,因为前者可能会将内容留在流的缓冲区中。
对于面向行的格式,使用 fgets()
仅读取整行,然后使用 例如 sscanf()
解析您阅读的内容。
运行 GDB 时看到的字符串实际上以第一个空字符结尾:
"rtestr18/04/2010rtest2r03/05/2010rtest3r05/08/2009rtest4rn 00"
之后的其他数据被忽略(使用普通str函数时);