0

I've been at this for a while and I can't seem to figure out what's happening. I give empty definitions for the structs in a header file so they are opaque.

typedef struct block_store block_store_t;
typedef struct block block_t;

In a different file I actually define them.

struct block_t{
    void* data;
};    

struct block_store_t{
     block_t* b;
 };

void create_struct(){
    block_store_t* bs = malloc(sizeof(block_store_t*));
    block_t* array = malloc(sizeof(block_t*) * 256);

    bs->b = array;  //error: dereferencing pointer to incomplete type
 }
6
  • Are the typedefs also known (aka included) in your "different" file? It seems the compiler doesn't know about the typedefs Commented Feb 16, 2018 at 1:31
  • I include the correct .h file in my .c file if that's what you're asking. Is there something else I need to do in the .h file? Commented Feb 16, 2018 at 1:34
  • 1
    block_store and block are incomplete... Perhaps you meant typedef struct block_store_t block_store_t; and etc... Commented Feb 16, 2018 at 1:37
  • 1
    You have block_t as a typedef for the type struct block, and similarly for struct block_store; that is, you need to define the type struct block, not struct block_t, so change: struct block_t { void* data; }; --> struct block { void* data; }; and struct block_store_t { block_t* b; }; --> struct block_store { block_t* b; }; Commented Feb 16, 2018 at 2:06
  • 2
    Also note that it is best (and idiomatic C) to call malloc() like: block_t *array = malloc(sizeof *array * 256);. That is, use an identifier instead of an explicit type as the operand for sizeof. This is less error-prone and easier to maintain. And don't forget to check for allocation failure.... Commented Feb 16, 2018 at 2:09

3 Answers 3

2

typedef the struct before using it in the another structure like

typedef struct block{
        void* data;
}block_t;    

typedef struct block_store{
     block_t* b; /* it works bcz you typedefed before only */
}block_store_t;

Also sizeof(block_store_t*) should be sizeof(block_store_t) as first one only allocate equal to struct pointer size but you may want to allocate equal to whole struct size.

block_store_t* bs = malloc(sizeof(block_store_t));/* allocate memory equal to sizeof structure, not just 4 bytes */
//block_t* array = malloc(sizeof(block_t) * 256);
block_t* array = malloc(sizeof(*array) * 256);/*preferable to use bcz it work for any data type */
Sign up to request clarification or add additional context in comments.

14 Comments

No, it should struct block_t because that's the user-defined type name.
Both malloc(sizeof(struct block_t)) and malloc(sizeof(block_t) are fine. 2nd one is correct if you did typedef.
bedbad I thought that looked funny as well but I was given the header file and told to implement them myself. @achal Thanks for the help and good catch on my bad malloc that went uncaught by the compiler
@OmegaCollision The best(and pretty much only) way to learn C is to read K&R C book and a Unix OS book, because that's where malloc and dynamic things come from. I can tell you from experience, your learning curve will be great and you'll save yourself a lot of time. You can finish it in a week and totally master C.
@bedbad -- K&R is a great book, but very out of date. Not the best book to learn from at first (in my opinion, but many agree with me on this). And there is no way to master C in one week.
|
2

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;
}

1 Comment

Detailed explanation. Good one.
0

You're making basic C mistakes. When you do memory allocation make sure you are allocation the right sizes. Size of a pointer to a struct will be the same as a size of any other pointer most probably and there will be an error when you'll try to address that region as a whole struct.

struct block_store* bs = malloc(sizeof(struct block_store));
struct block* array = malloc(sizeof(struct block) * 256);

Regarding typedefs - they are just aliases not to right long "struct name" Make sure they are visible.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.