Structures and Arrays, Part III

I’ve wrapped up most of the oddities about structure/pointer/array notation in the past two Lessons (Part I and Part II). All that’s left is for me to go insane and start allocating structures as pointers with all their members as pointers.

I’ll use the same player structure from the past two Lessons:

struct player {
    char name[32];
    char scores[10];
};

The conversion of a char array into a char pointer is easiest. For each player structure allocated, the name array must also be allocated, as shown in this code:

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

int main()
{
    struct player {
        char *name;
        int scores[10];
    } *p;
    int x,y;

    /* allocate structures */
    p = (struct player *)malloc( sizeof(struct player) * 3 );
    if( p==NULL )
    {
        fprintf(stderr,"Unable to allocate structures\n");
        exit(1);
    }

    /* allocate storage for name member */
    for( x=0; x<3; x++ )
    {
        p[x].name = (char *)malloc( sizeof(char) * 32 );
        if( p[x].name==NULL )
        {
            fprintf(stderr,"Unable to allocat string\n");
            exit(1);
        }
    }

    /* assign player names */
    strcpy((p+0)->name,"Billy Zlotnick");
    strcpy((p+1)->name,"Franny Blortz");
    strcpy((p+2)->name,"Oscar Papadapolous");

    /* create random scores */
    srand( (unsigned)time(NULL) );
    for( y=0; y<3; y++)
    {
        for( x=0; x<10; x++)
            (p+y)->scores[x] = rand() % 100;
    }

    /* output results */
    for( y=0; y<3; y++)
    {
        printf("%s's scores:\n",(p+y)->name);
        for( x=0; x<10; x++)
            printf(" %3d",(p+y)->scores[x]);
        putchar('\n');
    }

    return(0);
}

Structure p is allocated at line 15. Room is set aside for three structures.

For each structure allocated, a name pointer is allocated at Line 23. The format used is p[x].name. This format is valid because array notation is used; p is still a pointer, but for some reason the compiler is okay using dot notation with an array of pointers. Weird.

At Lines 34, 35, and 36, I use pointer math to access each p structure: (p+0)->name. In this format, the -> notation is required. Yet, if the statements were reformatted to use p[0].name, the dot is used. The compiler balks if you use p[0]->name.

For the scores array at Lines 43 and 51, array notation is retained. But what happens when scores is allocated as an array? This code demonstrates:

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

int main()
{
    struct player {
        char *name;
        int *scores;
    } *p;
    int x,y;

    /* allocate structures */
    p = (struct player *)malloc( sizeof(struct player) * 3 );
    if( p==NULL )
    {
        fprintf(stderr,"Unable to allocate structures\n");
        exit(1);
    }

    /* allocate storage for name and scores members */
    for( x=0; x<3; x++ )
    {
        p[x].name = (char *)malloc( sizeof(char) * 32 );
        p[x].scores = (int *)malloc( sizeof(int) * 10 );
        if( p[x].name==NULL || p[x].scores==NULL )
        {
            fprintf(stderr,"Unable to allocate storage\n");
            exit(1);
        }
    }

    /* assign player names */
    strcpy((p+0)->name,"Billy Zlotnick");
    strcpy((p+1)->name,"Franny Blortz");
    strcpy((p+2)->name,"Oscar Papadapolous");

    /* create random scores */
    srand( (unsigned)time(NULL) );
    for( y=0; y<3; y++)
    {
        for( x=0; x<10; x++)
            *((p+y)->scores+x) = rand() % 100;
    }

    /* output results */
    for( y=0; y<3; y++)
    {
        printf("%s's scores:\n",(p+y)->name);
        for( x=0; x<10; x++)
            printf(" %3d",*((p+y)->scores+x));
        putchar('\n');
    }

    return(0);
}

Storage for the scores array is allocated in the for loop at Line 23. Line 26 uses array notation to assign space for 10 int values.

The pointer notation required to reference each int value is shown at Lines 44 and 52: *((p+y)->scores+x) I’ll be honest and explain that coding this concoction wasn’t obvious.

My first attempt was to use (p+y)->*(scores+x). So the structure at address (p+y) references the value at address (scores+x). But this construction doesn’t work. Instead, the format relies upon obtaining an address offset first, then accessing the value:

*((p+y)->scores+x)

First, address (p+y) is calculated. Then, a reference is made to address scores+x. At this point (p+y)->scores+x references the location of an int value. To pull this value, the entire concoction is wrapped in parentheses and prefixed with the * operator.

At this point, I’ll stop the craziness. I think I covered nearly all the possibilities for weird notation within a structure. Though, if you can think of more, please let me know. I can handle it.

Leave a Reply