c-如何访问另一个结构中的双指针结构



我在访问结构中的双指针结构时遇到问题。

typedef struct monster
{
char *name;
char *element;
int population;
} monster;
typedef struct region
{
char *name;
int nmonsters;
int total_population;
monster **monsters;
} region;

region **
readRegion (FILE * infile, int *regionCount)
{

region **temp;
char garbage[50];
char garbage2[50];

char rName[50];
int monsterNum;

fscanf (infile, "%d %s", regionCount, garbage);
temp = malloc (*regionCount * sizeof (region *));

for (int i = 0; i < *regionCount; i++)
{
fscanf (infile, "%s%d%s", rName, &monsterNum, garbage2);
temp[i] = createRegion (inFile, rName, monsterNum);
}
return temp;
}
region *
createRegion (FILE * inFile, char *rName, int nMonsters)
{
region *r = malloc (sizeof (region));
char rMonster[50];
int rLength;
r->name = malloc ((strlen (rName) + 1) * sizeof (char));
strcpy (r->name, rName);
r->nmonsters = nMonsters;

for (int i = 0; i < nMonsters; i++)
{
r->monsters.name = (nMonsters * sizeof (r->monsters.name));
fscanf (in, "%s", rMonster);

r->monsters.name = malloc ((strlen (rMonster) + 1) * sizeof (char));
strcpy (r->monsters.name, rMonster);
}
return r;
}

希望我的代码是可读的,在那里你可以了解我试图用我的区域结构中的怪物指针做什么。任何关于如何访问和使用结构中的双结构指针的解释都会有所帮助。

我试图清理并重新解释您的createRegion,使其读起来更像传统的C:

region* createRegion(FILE * inFile, char *rName, int nMonsters) {
region *r = malloc(sizeof(region));
char buffer[1024];
r->name = strdup(rName);
r->nmonsters = nMonsters;
r->monsters = calloc(nMonsters, sizeof(monster*));
for (int i=0; i < nMonsters; i++) {
// Allocate a monster
monster *m = malloc(sizeof(monster));
fscanf(in,"%s", buffer);
m->name = strdup(buffer);
m->element = NULL; // TBD?
m->population = 1; // TBD?
// Put this monster in the monsters pointer array
r->monsters[i] = m;
}
return r;
}

这里的关键是你必须分配怪物。在这里,它是单独完成的,但你也可以分配为一块:

region* createRegion(FILE * inFile, char *rName, int nMonsters) {
region *r = malloc(sizeof(region));
char buffer[1024];
r->name = strdup(rName);
r->nmonsters = nMonsters;
// Make a single allocation, which is usually what's returned from
// C functions that allocate N of something
monsters* m = calloc(nMonsters, sizeof(monster));
// Normally you'd see a definition like m in the region struct, but
// that's not the case here because reasons.
r->monsters = calloc(nMonsters, sizeof(monster*));
for (int i=0; i < nMonsters; i++) {
fscanf(in,"%s", buffer);
m[i].name = strdup(buffer);
m[i].element = NULL; // TBD?
m[i].population = 1; // TBD?
// Put this monster in the monsters pointer array
r->monsters[i] = &m[i];
}
return r;
}

注意,我已经用一个简单的strdup调用切换出了非常古怪的基于strlen的代码。使用sizeof(char)也很奇怪,因为在任何你可能与之接口的计算机上,无论是嵌入式微控制器还是高级主机,都将为1。

由于您正在询问访问结构内部的双指针,我认为您的问题主要是关于这个函数:

region *
createRegion (FILE * inFile, char *rName, int nMonsters)
{
region *r = malloc (sizeof (region));
char rMonster[50];
int rLength;
r->name = malloc ((strlen (rName) + 1) * sizeof (char));
strcpy (r->name, rName);
r->nmonsters = nMonsters;

[点A]

到目前为止,一切都很好,但现在你开始偏离轨道了。

for (int i = 0; i < nMonsters; i++)
{
r->monsters.name = (nMonsters * sizeof (r->monsters.name));

请稍等。r->monsters的类型为monster **,但您正试图将其访问为monster。此外,r->monsters从未为其分配过值,因此您几乎无法安全地使用它

我认为这个想法一定是让r->monsters指向一个动态分配的monster *数组,循环分配并初始化怪物,并将指向它们的指针写入数组。

那么,您需要为数组分配空间,但您只需要或希望分配一次数组。在循环之前,在上面的A点,这样做:

r->monsters = malloc(nMonsters * sizeof(*r->monsters));  // a monster **

然后,在循环中,你需要为一个怪物分配空间,并为你的数组分配一个指针:*

r->monsters[i] = malloc(sizeof(*r->monsters[i]));  // a monster *

然后,要访问实际的monster对象,您需要取消引用并使用直接成员选择运算符(.(。。。

(*r->monsters[i]).name = /* ... */;

或者使用间接成员选择运算符(->(。。。

r->monsters[i]->name = /* ... */;

两者是等价的,但大多数C程序员似乎更喜欢后一种风格。

然而,在这一点上,我注意到在循环的主体中,您似乎试图对怪物的name成员进行两次单独的分配。这没有意义,第一次尝试肯定是没有意义的,因为你似乎在试图给指针分配一个数字。

fscanf (in, "%s", rMonster);

r->monsters.name = malloc ((strlen (rMonster) + 1) * sizeof (char));
strcpy (r->monsters.name, rMonster);

使用以上内容,并利用sizeof(char)定义为1的事实,似乎您想要的是

// ...
r->monsters[i]->name = malloc(strlen(rMonster) + 1);
strcpy (r->monsters[i]->name, rMonster);

最后,

}
return r;
}

请注意,对应于类型monster **中的两个间接级别,每次通过r->members访问单个怪物属性都需要两个级别的去引用。在上面的表达式中,一个由索引运算符[]提供,另一个由间接成员访问运算符->提供。


*或者你可以在循环之前一次性为所有怪物分配空间,在循环内部只初始化它们和指向它们的指针数组。monster **的使用表明了个人分配方法,但选择哪种方法在一定程度上取决于如何使用这些方法。这两个选项基本上可以互换,但并不完全等同。