The posted code shows block_t as a typedef for the type struct block, and similarly block_store_t is a typedef for struct block_store. OP needs to define the types struct block and struct block_store, not struct block_t and struct block_store_t. Change the definitions to:
struct block {
void *data;
};
struct block_store {
block_t *b;
};
Note also that there are errors in the calls to malloc() in the posted code. The first call needs to allocate storage for a block_store_t structure, so this should be something like:
block_store_t* bs = malloc(sizeof (block_store_t));
The second call needs to allocate space for 256 block_t structures:
block_t* array = malloc(sizeof (block_t) * 256);
There is an idiomatic way of writing this code in C that is less error-prone, avoiding the particular mistake made in the posted code. This idiom also results in code that is easier to maintain when types change during the lifetime of the code:
block_store_t *bs = malloc(sizeof *bs);
block_t *array = malloc(sizeof *array * 256);
Here, identifiers are used instead of explicit types as operands for the sizeof operator.
Note also that malloc() may return a null pointer if an allocation fails. This condition should be checked for and failures handled by the code.
Since the question suggests that there should be multiple files, here is an example solution with a header file and two source files:
A header file containing typedefs, struct definitions and function prototypes:
/* bstore.h */
#ifndef BSTORE_H
#define BSTORE_H
typedef struct block_store block_store_t;
typedef struct block block_t;
struct block {
void *data;
};
struct block_store {
block_t *b;
};
block_store_t * create_store(void);
#endif
A source file containing function definitions. Note that OP code contained create_struct() which returned void; it seems that such a function should return a pointer to block_store_t, but maybe OP has different goals. Here, the function create_store() does return a pointer to block_store_t. Also note that allocation errors are handled here by exiting with an error message; OP may elect to handle errors more gracefully:
/* bstore.c */
#include <stdio.h>
#include <stdlib.h>
#include "bstore.h"
block_store_t * create_store(void)
{
block_store_t *bs = malloc(sizeof *bs);
if (bs == NULL) {
perror("Failure in block store allocation");
exit(EXIT_FAILURE);
}
block_t *array = malloc(sizeof *array * 256);
if (array == NULL) {
perror("Failure in array allocation");
exit(EXIT_FAILURE);
}
bs->b = array;
return bs;
}
A source file containing main():
/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "bstore.h"
int main(void)
{
block_store_t *my_store = create_store();
for (size_t i = 0; i < 42; i++) {
(my_store->b[i]).data = "testing";
}
for (size_t i = 0; i < 42; i++) {
puts((char *) (my_store->b[i]).data);
}
free(my_store->b);
free(my_store);
return 0;
}
typedefs also known (aka included) in your "different" file? It seems the compiler doesn't know about thetypedefsblock_storeandblockare incomplete... Perhaps you meanttypedef struct block_store_t block_store_t;and etc...block_tas atypedeffor the typestruct block, and similarly forstruct block_store; that is, you need to define the typestruct block, notstruct block_t, so change:struct block_t { void* data; };-->struct block { void* data; };andstruct block_store_t { block_t* b; };-->struct block_store { block_t* b; };malloc()like:block_t *array = malloc(sizeof *array * 256);. That is, use an identifier instead of an explicit type as the operand forsizeof. This is less error-prone and easier to maintain. And don't forget to check for allocation failure....