简体   繁体   中英

How to access a double pointer structure in another structure

I'm having trouble accessing my double pointer struct within my structure.

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

Hopefully my code is readable where you can get the jist of what im trying to do with the monster** monsters pointer in my region struct. Any explnation on how to access and use a double struct pointer within a structure would help.

I've tried to clean up and re-interpret your createRegion to read a lot more like traditional 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;
}

Where the key here is you must allocate the monsters. Here it's done individually, but you could also allocate as a slab:

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

Note I've switched out the highly quirky strlen -based code with a simple strdup call. It's also very odd to see sizeof(char) used since on any computer you're likely to interface with, be it an embedded microcontroller or a fancy mainframe, that will be 1.

Inasmuch as you are asking about accessing a double pointer inside a structure, I think your issue is mostly about this function:

 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;

[Point A]

So far, so good, but here you start to run off the rails.

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

Hold on. r->monsters has type monster ** , but you are trying to access it as if it were a monster . Moreover, r->monsters has never had a value assigned to it, so there's very little indeed that you can safely do with it.

I think the idea must be that r->monsters is to be made to point to a dynamically-allocated array of monster * , and that the loop allocates and initializes the monsters, and writes pointers to them into the array.

You need to allocate space for the array, then, but you only need or want to allocate the array once. Do that before the loop, at Point A, above, something like this:

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

Then, inside the loop, you need to allocate space for one monster, and assign a pointer to that to your array: *

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

Then, to access the actual monster objects, you need to either dererference and use the direct member selection operator ( . ) ...

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

... or use the indirect member selection operator ( -> ) ...

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

. The two are equivalent, but most C programmers seem to prefer the latter style.

At this point, however, I note that in the body of the loop, you seem to be trying to make two separate assignments to the monster's name member. That doesn't make sense, and the first attempt definitely doesn't make sense, because you seem to be trying to assign a number to a pointer.

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

Using the above, then, and taking advantage of the fact that sizeof(char) is 1 by definition, it appears that what you want is

        // ...

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

And finally,

 } return r; }

Note well that corresponding to the two levels of indirection in type monster ** , each access to an individual monster property via r->members requires two levels of derferencing. In the expressions above, one is provided by the indexing operator, [] , and the other is provided by the indirect member access operator, -> .


* Or you could allocate space for all of the monsters in one go, before the loop, and inside the loop just initialize them and the array of pointers to them. The use of a monster ** suggests the individual allocation approach, but which to choose depends somewhat on how these will be used. The two options are substantially interchangeable, but not wholly equivalent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM