【问题标题】:Dynamic fscanf into an array动态 fscanf 成数组
【发布时间】:2019-05-11 15:14:27
【问题描述】:

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

例如我的结构是:

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++
}

我该怎么做呢?

【问题讨论】:

  • favouriteFood 意味着包含“wet,dry,whiskers”还是包含“wet”、“dry”、“whiskers”的数组?
  • 啊,我的道歉,应该说清楚。 wet,dry,whiskers 都是数组中的单独文本,所以 "wet","dry","whiskers"

标签: c file input scanf


【解决方案1】:

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

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 个字符...或者将其设为 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 将它保存在它读取的缓冲区中,所以你可以用它来判断你是否已经完成了所有食物的处理(你还需要删除它从最后的食物开始)。或者,如果您没有它,您知道该行较长,您需要阅读更多内容。但根据您的示例数据,这似乎不太可能。

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

【讨论】:

  • 嗨,克里斯,感谢您的回复。从你给我的来看,这一切似乎都很完美,直到它需要添加最喜欢的食物,此时它似乎崩溃了。它似乎也只适用于一行文本。我已将代码放在:github.com/DcoltGaming/C - 你有没有机会告诉我我做错了什么?谢谢:)
  • 您遗漏的主要内容是您没有增加i。我看不出它会崩溃的任何原因。也许您的一种动物类型超过 10 个字符?
  • 啊...也许它实际上并没有崩溃...我已经放入了 i++ 但是我似乎只有内存地址? imgur.com/a/4VojGpI
  • 你创建的字符串的内存地址?
  • 可能是,但它似乎并没有真正创建字符串
猜你喜欢
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 2013-02-08
  • 2021-11-15
  • 2015-06-12
  • 2019-04-27
相关资源
最近更新 更多