数据文件:
classpath 'io.fabric.tools:gradle:1.+'
读取代码:
Newton 30 United Kingdom Scientist
Maxwell 25 United Kingdom Mathematician
Edison 60 United States Engineer
我编写了一个程序,使用#define MAX_NAME 50
#define MAX_COUNTRY 25
#define MAX_PROFILE 20
struct person
{
char *name;
int age;
char *country;
char *profile;
};
struct person pObj;
pObj->name = (char *) malloc(sizeof(MAX_NAME));
pObj->country = (char *) malloc(sizeof(MAX_COUNTRY));
pObj->profile = (char *) malloc(sizeof(MAX_PROFILE));
fscanf(fPtr,"%s\t%d\t%s\t%s\n",pObj->name,&pObj->age,pObj->country,pObj->profile);
将制表符分隔的记录读取为结构。我可以通过fscanf()
和strtok()
函数执行相同的操作。但是,如果我使用strsep()
,则不得不使用strtok()
函数来加载atoi()
字段。但是我不想使用该age
函数。因此,我只是使用atoi()
直接从FILE流缓冲区读取age作为Integer。工作正常。但是对于某些记录,国家字段为空,如下所示。
fscanf()
当我阅读第二条记录时,Newton 30 United Kingdom Scientist
Maxwell 25 Mathematician
Edison 60 United States Engineer
不会在国家/地区字段中填充空字符串,而是已使用个人资料数据填充。我们了解fscanf()
就是这样工作的。但是,即使文件中为空,也可以选择扫描国家/地区字段吗?我可以不使用年龄fscanf()
来做到这一点吗?即按相应的类型读取字段,但不按字符串读取所有字段。
答案 0 :(得分:2)
%s
转换规范会跳过输入中的任何空格(空白,制表符,换行符等),然后读取非空格直到下一个空格字符。格式字符串中出现的\t
导致fscanf()
跳过零个或多个空格字符(不仅仅是制表符)。
您有:
fscanf(fPtr,"%s\t%d\t%s\t%s\the n", pObj->name, pObj->age, pObj->country, pObj-profile);
您需要传递指向年龄的指针,并且需要在->
和pObj
之间使用箭头profile
(请进行编译的邮政编码;在此位置,这不会激发您的信心)是这样的错误):
fscanf(fPtr,"%s\t%d\t%s\t%s\the n", pObj->name, &pObj->age, pObj->country, pObj->profile);
给出第一行输入:
Newton 30 United Kingdom Scientist
fscanf()
将Newton
读入pObj->name
,30
读入pObj->age,
美国into
国家and
王国into
{一般来说,{1}} pObj-> profile .
fscanf()和家人对空白非常随意。大多数转化会跳过前导空白。
在分配了4个值之后,格式末尾有\the n"
。该标签页跳过了Kingdom
和Scientist
之间的空格,但是数据与he n
不匹配,因此扫描停止了—并不是您更明智。>
下一个操作将在此操作停止的地方进行,因此将为下一个pObj->name
分配Scientist
,然后pObj->age
转换将失败,因为Maxwell
不会代表一个整数。转换停止在该fscanf()
上。
因此问题继续存在。您在问题中显示的代码无法获得您要求的输出。
如果您坚持必须使用fscanf()
,则需要使用%24[^\t]
之类的扫描集来读取国家/地区。但是您最好使用fgets()
或POSIX函数getline()
来读取整行输入,然后也许使用sscanf()
,但更可能使用strcspn()
或{{1} },从标准C(或者可能是strpbrk()
或(最好是POSIX strtok()
或Windows strtok_r()
,或非标准strtok_s()
)将行拆分到选项卡上的字段中。请注意,strsep()
等人并不关心字段之间的分隔符(在您的情况下为制表符)有多少重复;您不能将它们带空字段。您可以使用strtok_r()
,strcspn()
和strpbrk()
来标识空白字段。
格式字符串已修改为:
strsep()
这是行不通的,但现在可以对其进行调整,以使其起作用。
fscanf(fPtr,"%s\t%d\t%s\t%s\n", pObj->name, &pObj->age, pObj->country, pObj->profile);
Beware trailing white space in scanf()
format strings。前导空格会跳过前几行留下的任何换行符,并跳过一行中的任何前导空格。 if (fscanf(fPtr," %49[^\t]\t%d\t%24[^\t]\t%19[^\n]", pObj->name, &pObj->age, pObj->country, pObj->profile) != 4)
…handle a format error…
查找多达49个非制表符;该选项卡是可选的,并且匹配任何空格序列,但是第一个字符将是一个选项卡,除非名称太长。然后,它读取一个数字,更多可选的空格(它不必是制表符,但除非数据格式错误,否则它将是空白),然后再读取多达24个非制表符,又是空格(其中第一个字符将是除非存在格式问题,否则应为标签页),以及最多19个非标签页。除非存在格式问题,否则下一个字符应为换行符。