有一个文件a.txt如下所示:
1 abc
2
3 jkl
我想将此文件的每一行都读为int
和一个字符串,如下所示:
fp = fopen("a.txt", "r");
while (1) {
int num;
char str[10];
int ret =fscanf(fp, "%d%s", &num, str);
if (EOF == ret)
break;
else if (2 != ret)
continue;
// do something with num and str
}
但是有一个问题,如果a.txt中的一行只包含一个数字,没有字符串(就像第2行一样),那么上面的代码就会卡在那一行。
那么有什么方法可以跳到下一行吗?
答案 0 :(得分:2)
分两步完成:
fgets()
阅读整行。这假设你可以对你想要支持的行数设置一个简单的静态限制,但这种情况经常发生。sscanf()
检查并解析该行。这可以解决您遇到的问题,对于像这样的问题通常是更好的方法。
更新:尝试回复您的评论。我看到它的方式,最简单的方法是始终读取整行(如上所述),然后解析您认为它包含的两个字段:数字和字符串。
如果您使用sscanf()
执行此操作,则可以使用返回值来确定其运行方式,就像您在代码中尝试使用fscanf()
一样:
const int num_fields = sscanf(line, "%d %s", &num, str);
if( num_fields == 1 )
; /* we got only the number */
else if( num_fields == 2 )
; /* we got both the number and the string */
else
; /* failed to get either */
不确定何时不“需要”字符串;它要么存在,要么不存在。
答案 1 :(得分:1)
如果字符串的第一个字符是\r or\n
,则这将是一个空字符串。您可以使用比较。如果单词中包含空格(或空行),则fscanf()不合适。在这种情况下,最好使用fgets()
答案 2 :(得分:1)
如何解决"使用fscanf":
在int
之后,查找空格(不要保存),然后查找不是char
的{{1}}。
'\n'
如果将某些内容扫描到int num;
char str[10];
#define ScanInt "%d"
#define ScanSpacesDontSave "%*[ ]"
#define ScanUntilEOL "%9[^\n]"
int ret = fscanf(fp, ScanInt ScanSpacesDontSave ScanUntilEOL, &num, str);
if (EOF == ret) break;
else if (1 == ret) HandleNum(num);
else if (2 == ret) HandleNumStr(num, str);
else HadleMissingNum();
, ret
将为2,否则str
通常为1.上述技巧不是扫描在ret
之后'\n'
。因此代码不能在int
之后使用"%s"
或" "
,它们都消耗所有(领先)空白区域。 下一次 "%d"
调用将通过fscanf()
消耗'\n'
作为领先空白消费的一部分。
次要注意:使用"%d"
读取行然后解析缓冲区通常是一种更好的方法,但编码目标可能会排除这种情况。