Nested array struct in C

Viewed 99

Why the content is not printed well (e.g. Segmentation Fault/NULL)? I'm passing the entire nested struct (i.e. the array list lp) to the main list. Any suggestion? I spent two days to understand what I wrong without success. I would to have an explanation about it.

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

struct list
{
    char *a;
    char *b;
} lp[10];

typedef struct
{
    int k;
    struct list thelist[2];
} palist;

int main()
{

    lp[0].a     = "One";
    lp[0].b     = "Two";

    lp[1].a     = "Three";
    lp[1].b     = "Four";

    palist final_list = {10, *lp};

    printf("%s, %s", final_list.thelist[1].a, final_list.thelist[1].b);

    return 0;
}
2 Answers

What you have to understand is that on access, an array is converted to a pointer to the first element (subject to 4-exceptions not relevant here) C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)

When you attempt to initialize thelist with *lp you are attempting to initialize an array of struct list from the first element in lp. Assuming you change the intialization from {10, *lp} to (10, lp) that still will not work because now lp is a pointer to the first element which you attempt to use to initialize an array.

In order to accommodate the array/pointer conversion, you need to declare thelist as a pointer not an array, e.g.

typedef struct
{
    int k;
    struct list *thelist;
} palist;

(You can initialize a pointer with a pointer and all will be well)

Now using the initializer {10, lp} will provide a pointer for the initialization of thelist and your assignment will work (but you must keep track of the number of elements that are valid -- final_list[2].... would invoke Undefined Behavior as the elements 2 and beyond are not initialized)

Your total code would be:

#include <stdio.h>

struct list
{
    char *a;
    char *b;
} lp[10];

typedef struct
{
    int k;
    struct list *thelist;
} palist;

int main(void) {

    lp[0].a     = "One";
    lp[0].b     = "Two";

    lp[1].a     = "Three";
    lp[1].b     = "Four";

    palist final_list = {10, lp};

    printf("%s, %s\n", final_list.thelist[1].a, final_list.thelist[1].b);

    return 0;
}

There are many other ways to initialize or assign this list in the form with the array

typedef struct
{
    int k;
    struct list thelist[2];
} palist;

for example

    palist final_list = {10, {lp[0], lp[1]}};
    final_list = (palist){10, {lp[0], lp[1]}};
    final_list = (palist){10,};
    memcpy(final_list.thelist, lp, sizeof(final_list.thelist));

https://godbolt.org/z/fUjLtE

Related