首页 > 解决方案 > 动态 fscanf 成数组

问题描述

我正在尝试将一些文本放入我的数组的结构部分中,这是一个包含部分文本的数组。

例如我的结构是:

struct animal
{
    char animal_Type[11];
    int age;
    int numberOfLegs;
    int walksPerDay;
    char favoriteFood[];
};

然后,我将输入以下内容:

dog,2,4,2,biscuits,wet
cat,5,4,0,biscuits,wet,dry,whiskers
bird,1,2,0,birdseed,biscuits,bread,oats,worms,insects,crackers

我有一个可行的解决方案,可以将每天步行的所有值放入结构中,但是我希望能够将食物放入最喜欢的食物中。我有一个动态数组,但我不确定如何将剩余的文本读入 favoriteFood 数组。

使用的代码是:

fp = open("animals.txt","r");
struct animal *animal = malloc(sizeof(sturct animal)*3);
int i = 0;
if(fp != NULL) {
     while(i < 3) {
fscanf(fp,"%s %d %d %d %s",
     animal[i].animal_Type,
     animal[i].age,
     animal[i].numberOfLegs,
     animal[i].walksPerDay,
     animal[i].favoriteFood); // need to be able to enter the string of food into here
i++
}

我该怎么做呢?

标签: cfileinputscanf

解决方案


首先,您struct与您在评论中所说的不符。

char favoriteFood[];

上面是一个数组char,所以不可能保存最喜欢的食物列表,除非它是一个字符串。而且由于数组的大小未指定,因此您也无法像以前那样填充它。相反,你真正想要的是

char **favoriteFood;
unsigned int favoriteFoodSize;

这将让您创建一个扩展的字符串列表,以适应您需要容纳的任何数据。

至于阅读它,最好的方法是在使用中阅读整行,fgets然后使用诸如strtok通过分隔符分隔行的东西。首先定义一个非常大的字符串来保存整行,并定义一个char *来保存每个字段。

char buffer[1024];
char *token;

然后到主循环将是这样的:

while(fgets(buffer,1024,fp)) {
    token=strtok(buffer,",");
    strcpy(beasts[i].animal_Type,token);

    token=strtok(NULL,",");
    beasts[i].age = atoi(token);

    /* etc... */
}

您需要检查是否token曾经NULL应对短线的可能性并相应地处理它。并且还要确保复制到的字符串animal_Type不超过 10 个字符……或者将其设为 a char *,这样您就可以拥有任意大小的字符串。

对于favoriteFood,您需要使用realloc增加它的大小以适应添加的每个新食物,并继续遍历字符串,直到用完标记。

token=strtok(NULL,",");
if(token) {
    beasts[i].favoriteFood=malloc(sizeof(char *));
    beasts[i].favoriteFood[0]=strdup(token); // Need to index using 0 as favoriteFoodSize won't have a value yet
    beasts[i].favoriteFoodSize=1;

    token=strtok(NULL,",");
    while(token) {
        beasts[i].favoriteFood=realloc(beasts[i].favoriteFood,(beasts[i].favoriteFoodSize+1)*sizeof(char *));
        beasts[i].favoriteFood[beasts[i].favoriteFoodSize]=strdup(token);
        beasts[i].favoriteFoodSize++;

        token=strtok(NULL,",");
    }
}

最后一个食物将\n在其中fgets保存它读取的缓冲区,因此您可以使用它来判断您是否已经完成了所有食物的处理(您还需要从最后一个食物中删除它)。或者如果你没有它,你知道这条线更长,你需要阅读更多内容。但根据你的样本数据,这似乎不太可能。

而且由于您正在分配大量内存,因此您应该确保检查返回的值以确保您没有耗尽内存。


推荐阅读