Declare innerStruct as an inner *, rather than a struct inner if you want to use malloc().
As you've declared it, the memory for inner is allocated when you create an outer.
Note also that, since you've used typedef, you don't need the struct keyword when you declare a variable of that type.
Here's a corrected version of your code that compiles and runs:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char address[32]; // 32 chars are allocated when an inner is created
} inner;
typedef struct {
inner innerStruct; // innerStruct is allocated when an outer is created
} outer;
typedef struct {
inner *innerStruct; // innerStruct must be allocated explicitly
} outer2;
int main(int argc, char *argv[]) {
int i = 0;
outer *outerArray;
outer2 *outer2Array;
outer *outerReference;
outer2 *outer2Reference;
/* create 20 outer structs (should check for out-of-mem error) */
outerArray = malloc(20 * sizeof(outer));
for (i = 0; i < 10; ++i) {
outerReference = outerArray + i; // ptr to i'th outer
// Note: innerStruct.address bcz it's a structure
sprintf(outerReference->innerStruct.address, "outer struct %d", i);
}
/* create 20 outer2 structs */
outer2Array = malloc(20 * sizeof(outer2));
/* for each outer struct, dynamically allocate 10 inner structs */
for (i = 0; i < 10; ++i) {
outer2Reference = outer2Array + i;
outer2Reference->innerStruct = malloc(sizeof(inner));
// Note: innerStruct->address bcz it's a pointer
sprintf(outer2Reference->innerStruct->address, "outer2 struct %d", i);
}
/* print all the data and free malloc'ed memory */
for (i = 0; i < 10; ++i) {
printf("outer: %-20s, outer2: %-20s\n",
outerArray[i].innerStruct.address,
outer2Array[i].innerStruct->address);
free(outer2Array[i].innerStruct);
}
free(outer2Array);
free(outerArray);
return 0;
}