Structures of Pointer Structures in Structures

Nested structures present another opportunity for pointers to growl in your code. The struggle is knowing which structure member operator to use — and where.

The following code shows a nested structure. The firstlast structure contains strings first and last. It’s nested inside the person structure, which is then filled with data. Because no pointers lurk within the code, the standard structure member operator (.) is used:

#include <stdio.h>
#include <string.h>

int main()
{
    struct firstlast { char first[24]; char last[24]; };
    struct person { struct firstlast name; int age; };
    struct firstlast washington;
    struct person president;

/* fill the structure */
    president.name = washington;
    strcpy(president.name.first,"George");
    strcpy(president.name.last,"Washington");
    president.age = 57;

/* display */
    printf("President %s %s was %d years old.\n",
        president.name.first,
        president.name.last,
        president.age);

    return(0);
}

You may see a warning upon compile because structure washington is used in Line 12 before its members are assigned values. That’s not a problem in this code.

Here’s the output:

President George Washington was 57 years old.

In the following variation, the structure members first, last, and age are all pointers:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    struct firstlast { char *first; char *last; };
    struct person { struct firstlast name; int *age; };
    struct firstlast washington;
    struct person president;

/* allocate storage */
    washington.first = (char *)malloc(24 * sizeof(char));
    washington.last = (char *)malloc(24 * sizeof(char));
    president.age = (int *)malloc(1 * sizeof(int));
    if( washington.first==NULL
        || washington.last==NULL
        || president.age == NULL )
    {
        puts("Unable to allocate memory");
        exit(1);
    }

/* fill the structure */
    president.name = washington;
    strcpy(president.name.first,"George");
    strcpy(president.name.last,"Washington");
    *president.age = 57;

/* display */
    printf("President %s %s was %d years old.\n",
        president.name.first,
        president.name.last,
        *president.age);

    return(0);
}

The bulk of the code, Lines 12 through 22, deals with allocating space for the three pointers. Yet, the member operator is always the dot. That’s because the structure variables themselves aren’t pointers.

By the way, the variable president.age is a memory location and the variable *president.age is the value at that location. This type of pointer notation is required, even within a structure. You see that usage in Lines 28 and 34.

Regardless of what happens with the variables, when the structure itself is a pointer, you must use the structure pointer member operator:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    struct firstlast { char first[24]; char last[24]; };
    struct person { struct firstlast *name; int age; };
    struct firstlast *washington;
    struct person *president;

/* allocate storage */
    washington = (struct firstlast *)malloc(1 * sizeof(struct firstlast));
    president = (struct person *)malloc(1 * sizeof(struct person));
    if( washington==NULL || president==NULL )
    {
        puts("Unable to allocate memory");
        exit(1);
    }

/* fill the structure */
    president->name = washington;
    strcpy(president->name->first,"George");
    strcpy(president->name->last,"Washington");
    president->age = 57;

/* Display */
    printf("President %s %s was %d years old.\n",
        president->name->first,
        president->name->last,
        president->age);

    return(0);
}

Both structures washington and president are pointers. Therefore, the -> operator is used to access any of their members, as shown above.

Because washington is a pointer, the name member in structure person is also declared as a pointer, as shown in Line 8.

If you were to use pointer members, as shown in the second example, then you’d have quite a few additional malloc() statements, but the member notation changes only when the structure itself is a pointer.

If you do use pointer members, remember that you must allocate storage for the structure first, confirm that it’s available, and then allocate storage for the members. Also, you must use the following format when referencing the pointer age inside pointer variable president:

*president->age

To allocate the variable’s storage, you omit the * operator, but you must still use president->age when structure president is a pointer.

Leave a Reply