我在访问结构中的双指针结构时遇到问题。
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 **
的使用表明了个人分配方法,但选择哪种方法在一定程度上取决于如何使用这些方法。这两个选项基本上可以互换,但并不完全等同。