Pete Pete - 24 days ago 7
C Question

C Syntax for a dynamic-allocated array within a struct within a dynam array within a struct

I have a C syntax question which is driving me crazy. I've defined some container structs:

typedef struct AStruct {
int importantData1;
int importantData2;
} A;

typedef struct BStruct {
A* arr1; // dynamic array of A structs
} B;

typedef struct CStruct {
B* arr2; // dynamic array of B structs
} C;


As you can guess, each A struct hold a part of my program's data. Each B struct holds an array of A's and each C struct holds an array of B's. I anticipate the need for only one C struct. So total amount of data with my C struct will be:

total data in C == (num of B's) * (num of A's)


The tricky part is I don't know how many A's and B's I'll need at compile time. This means I can't hardwire the array sizes; they must be dynamically allocated.

There's gotta be a way to do this. Here's my clunky attempt:

void makeContainers(C* x, int numB, int numA){
x->arr2 = (B*)malloc(numB * sizeof(B)); // allocate an array of empty B structs
B* Bptr;
int i;
for(i=0; i<numB; i++){
Bptr = x->arr2[i]; // Bptr is one of the B's in C's arr2
Bptr = (A*)malloc(numA * sizeof(A)); // Allocate an array of empty A stucts
}
}

int main() {
C* bigContainer = (C*)malloc(sizeof(C)); // Allocate the C struct
makeContainers(bigContainer, 8, 8); // populate C with B's and A's

return 0;
}


This looked great on paper... but the compiler hates the
Bptr = x->arr2[i];
line. (Compiling with GCC on Linux) Here's the error:

[Linux]$ gcc -Wall setsInSets.c
setsInSets.c: In function ‘makeContainers’:
setsInSets.c:23:8: error: incompatible types when assigning to type ‘struct B *’ from type ‘B’
Bptr = x->arr2[i]; // Bptr is one of the B's in C's arr2
^


The "to type struct B from type B" part confuses me. Not sure what the compiler is trying to tell me here.

Also... This is kinda a C 101-type question, but I'm not certain I completely understand what the first line in makeContainers() is doing:

x->arr2 = (B*)malloc(numB * sizeof(B));


Here I am allocating memory for an array of B structs... but does that mean when this command is finished, I literally have an array of "empty" B structs ready to go? Or have I just set aside the memory, but the memory itself contains just "garbage"? In other words, do I have to walk the
x->arr2
array and
malloc()
an individual B struct?

I know this is probably a duplicate question - but I ask it anyway because I think the "struct within a dynamic array within a struct within a dynamic array" nature of this question is pretty specific.

Thanks!
-Pete

Answer

x->arr2 is pointer to an array of B structs

x->arr2[i] is dereferencing one element in the array i.e. a B struct

To set a pointer you need the address of the struct

B* Bptr = &(x->arry[i]);

or more conveniently

B* Bptr = x->arry + i;

I would suggest you write the size of the array in your struct as well, it may come in handy later.

e.g.

typedef struct BStruct {
    size_t elements;        // to know how many A structs 
    A* arr1; 
} B;

EDIT:

This part of the code

Bptr = x->arr2 + i;         // Bptr is one of the B's in C's arr2
Bptr = malloc(numA * sizeof(A)); 

makes no sense, you first assign Bptr, then assigning it to another address.