0

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

Pete
  • 1,511
  • 2
  • 26
  • 49
  • `x->arr2[i]` evaluates to a `B` object, not a pointer. Maybe you meant to write `Bptr = x->arr2`? – Jezor Nov 14 '16 at 19:32
  • 1
    [Don't cast malloc in C](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar Nov 14 '16 at 19:32
  • Those are not arrays at all. They are structs so you can't do `x->arr2[i]` but if you want to access, for example, `importantData1`, you can actually do `x->arr2->arr1->importantData1` – Nick Rameau Nov 14 '16 at 19:36
  • `Bptr = x->arr2[i];`should be `Bptr = x->arr2 + i;` or `Bptr = &x->arr2[i];` – alk Nov 14 '16 at 20:00
  • @Jezor Yes! You're totally right. I see it now. Its so easy to misunderstand what your C pointer really dereferences to. Thank you! – Pete Nov 14 '16 at 23:43
  • @NickRameau Thanks Nick. You are right about how it access importantData1. Once I saw your answer, I realized what I'd done wrong. – Pete Nov 14 '16 at 23:45
  • @alk Yep, I you're totally right. My syntax looks good now – Pete Nov 14 '16 at 23:45

1 Answers1

3

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.

AndersK
  • 35,813
  • 6
  • 60
  • 86
  • This is very, very clear, thank you. My syntax works now. Adding the size into the struct is a stroke of genius, I've already implemented it. Nice! – Pete Nov 14 '16 at 23:47