1

I've read and looked at some example of flexible array members but I am not exactly sure how to add and read elements of this variable length array.

typedef struct School {
    char *name;
    char *courses[]; //Flexible Array Member
} School;

1) Can someone please show me an example of how I can add an element to this Flexible Length Member and print it after it is stored.

2) I also would like to know how to malloc it correctly. Based on what I have read about Flexible Array Members, we would need to add more space for the flexible array member and can't just use sizeof(School);. My only issue is how do I know how much do add for that flexible member.

8
  • You will find an answer here: stackoverflow.com/questions/5478706/… Commented Jan 24, 2016 at 0:31
  • You need to either add struct member for the actual number of courses allocated for the structure or make the courses array end with a NULL pointer. Commented Jan 24, 2016 at 0:32
  • Allocate the structure with malloc(sizeof(School) + n * sizeof(char*)) Commented Jan 24, 2016 at 0:33
  • @chqrlie shouldnt it end with a null anyways since it is a array? Commented Jan 24, 2016 at 0:33
  • No, arrays do not necessarily end with a NULL, it is a matter of convention: either you know how many elements are allocated for the array and you give this information to all users of the structure, or you add a final NULL element when you allocate the array and users will look for the NULL element. Commented Jan 24, 2016 at 0:36

3 Answers 3

1

You should modify the struct to add the number of courses present in the allocated structure:

typedef struct School {
    char *name;
    int ncourses;
    char *courses[]; //Flexible Array Member
} School;

Say you have 2 schools, one with 3 courses, one with 2. You would allocate the structures this way:

School *mc = malloc(offsetof(struct School, courses) + 3 * sizeof(char *));
mc->name = strdup("Math College");
mc->ncourses = 3;
mc->courses[0] = strdup("Math 101");
mc->courses[1] = strdup("Math 102");
mc->courses[2] = strdup("Math 103");

School *ps = malloc(offsetof(struct School, courses) + 2 * sizeof(char *));
ps->name = strdup("Psycho School");
ps->ncourses = 2;
ps->courses[0] = strdup("Psycho 101");
ps->courses[1] = strdup("Unknown 404");

As you can see, elements of the variable array are accessed like any other array elements. The malloc call allocates the appropriate size in bytes for the struct members and the array elements (here char * pointers), that are located at the end of the structure.

You could use a generic function to allocate and initialize such structures:

School create_school(const char *school_name, int ncourses, char *courses[]) {
    School *sp = malloc(offsetof(struct School, courses) + ncourses * sizeof(char *));
    sp->name = strdup(school_name);
    sp->ncourses = ncourses;
    for (int i = 0; i < ncourses; i++) {
        sp->courses[i] = strdup(courses[i]);
    }
    return sp;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you I understand now. Just one quick question, would it be possible just to allocate the memory for the struct first and then afterwards realloc the extra needed for the flexible array?
@Billy: yes that would be possible, but you would need to update the pointers that refer to this structure everywhere. It may not be so easy if such a pointer was passed to a function in your call chain. Just updating your caller's local variable requires that it passes you a pointer to them.
0

The exact formula for computing the required size of your structure is:

size_t need = offsetof(struct School, courses) + num_courses * sizeof(char *);

Note the use of offsetof. Some people use sizeof, but this can introduce memory overhead due to structure padding.

2 Comments

@michaelmaeyer could you please show me how to add an elemet to the array. Im a still a bit confused about that.
The use of offsetof() works, but sizeof does not "introduce memory overhead due to structure padding". The C standard says, for the case of flexible array members, that "the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length." Which means that sizeof(struct School) and offsetof(struct School, courses) are equivalent.
0

Essentially the technique is to dynamically allocate enough memory for the struct, plus the elements of the last array.

School *data = malloc(sizeof(*data) + number * sizeof(*(data->courses)));

for (i = 0; i < number; ++i)
{
     const char hello[] = "Hello";
     data->courses[i] = malloc(strlen(hello) + 1));   /* sizeof char is 1 by definition */
     strcpy(courses[i], hello);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.