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.