0

I really have no idea how to correctly allocate memory for an array of struct that is defined in the header. The header code looks like this:

header.h

typedef struct _Transform Transform;

header.c

struct _Transform{
    char c;
    //the actual operation which is an union
    Operation o;
};

Should in my main program do something like this?

program.c

#include "header.h"

Transform **transform = calloc( MAX_NO_OF_TRANSFORMS, sizeof( Transform* ) );
if(!transform ) {
    perror("Error allocating memory for transform");
    exit(EXIT_FAILURE);
}
for(i = 0; i < MAX_NO_OF_TRANSFORMS; i++)
    transform[i] = calloc( 1, sizeof( Transform* ) );

If so, how should I then call it? I have an error when I try calling

transform[0].c = 'a';

By the way, the header is correctly linked and working. Thank you!

7
  • 1
    Do you want it statically allocated, or dynamically? Do you want a 1D array, or 2D array? Please clarify. Allocating an array of struct _Transform is as simple as struct Transform array[ARRAY_LENGTH], but from your code it looks like you want something else. Commented Mar 19, 2014 at 11:41
  • Sorry, I want a 1D array, but I cannot do Transform array[ARRAY_LENGTH] because struct is defined in the in header. Commented Mar 19, 2014 at 11:48
  • Why can't you? As long as a definition of struct _Transform is in scope, you can declare an array of it. You can include the header and then declare the array as Transform transform[MAX_NO_OF_TRANSFORMS] in the source file. It is overkill to use dynamic memory in this case, especially since you seem to have an upper bound for the array size known at compile time. Commented Mar 19, 2014 at 11:50
  • @FilipeGoncalves: if I do this struct _Transform tr[MAX_NO_OF_TRANSFORMS]; I get an error in return: array type has incomplete element type| Commented Mar 19, 2014 at 11:54
  • That's because there isn't a structure definition in scope - you lied to me. If the structure is defined in the header and the header is included, it must work. Or is the structure definition elsewhere? What are the contents of the header file you are including? Please update your question with this. Commented Mar 19, 2014 at 11:56

3 Answers 3

2

You will never be able to declare an array in program.c without having a structure definition in scope. The header file does not provide sufficient information to make the compiler know the size of Transform, so you can't declare an array of it in program.c.

The allocations for pointer to pointer to Transform work because the compiler doesn't need to know the size of Transform, since the pointed-to object is a pointer itself.

Move the structure definition into the header file. In other words, header.h should be:

header.h

struct _Transform{
    char c;
    //the actual operation which is an union
    Operation o;
};

typedef struct _Transform Transform;

And now, in program.c, you can declare a statically allocated array like so:

Transform transform[MAX_NO_OF_TRANSFORMS];

There is no need to use dynamically allocated memory in your code; it is overkill and utterly unnecessary, given the discussion we had in the comments section.

UPDATE

Since you seem to be new to this sort of stuff, I will give you another hint: always use include guards in your header files to avoid weird errors from the compiler due to multiple inclusion. For example, if you include header1.h and header2.h in program.c, and header2.h already includes header1.h, you will get multiple definition errors when compiling program.c (it's as if you included the same file twice). An include guard protects against this. A typical usage goes like this:

header.h

#ifndef TRANSFORM__STRUCT__HEADER
#define TRANSFORM__STRUCT__HEADER
struct _Transform{
    char c;
    //the actual operation which is an union
    Operation o;
};

typedef struct _Transform Transform;
#endif

This is a widely used technique. Basically, it works by defining a preprocessor symbol the first time the file is included - if it is included again, #ifndef will evaluate to false, and nothing will be included.

Sign up to request clarification or add additional context in comments.

5 Comments

Wow you really helped me out! I never knew you could do that in the header.h file. I thought all definitions should be in header.c; My bad for not knowing this. You solved 2 of my problems. Thank you! :)
And you made my work from now on A LOT more easier! :)
@SebastianLuke You can do pretty much anything in the header file. In general, structure definitions that are shared among multiple source files must be placed in a header file and included by the source files. I am also updating my answer with a known workaround to avoid including the same file multiple times.
using #ifndef HEADER_H_INCLUDED #define HEADER_H_INCLUDED?
@SebastianLuke Exactly. Good that you already know it - don't forget to do it, or you will quickly have weird errors
0

Sebastian,

This:

transform[i] = calloc( 1, sizeof( Transform* ) );

Should be changed to:

transform[i] = calloc( 1, sizeof( Transform ) );

You need to allocate enough memory to store the record - the first way, you just allocate enough memory for a pointer to Transform.

3 Comments

I thought so, but I get this in return: error: invalid application of 'sizeof' to incomplete type 'Transform'|
You have to use the typedef, as suggested by others.
From the first moment I wrote the structure, I used typedef :) Later I found what the problem was, but still: thanks! :)
0

There are a few problems with your code. First, the following statement

transform[i] = calloc(1, sizeof(Transform *));

allocates memory to hold a pointer to a Transform object, not a Transform object itself.

Second, sizeof operates during compile time except for variable-length array objects. The type name Transform in the scope of file program.c is an incomplete type because its size cannot be determined without its definition which is resolved during linking phase. You should move your structure definition to the header.h file.

// header.h

typedef struct _Transform {
    char c;
    //the actual operation which is an union
    Operation o;
} Transform;

Also, you should modify your program.c.

// program.c

// dynamically allocate an array to hold pointers to Transform objects

Transform **transform = calloc(MAX_NO_OF_TRANSFORMS, sizeof *transform);
if(!transform) {
    perror("Error allocating memory for transform");
    exit(EXIT_FAILURE);
}



for(i = 0; i < MAX_NO_OF_TRANSFORMS; i++) {
    // allocate memory to hold Transform objects and make the array element 
    // point to it. You can also replace **transform with *transform[i] in 
    // the calloc call.

    transform[i] = calloc(1, sizeof **transform);

    // check for NULL
    if(transform[i] == NULL) {
        perror("Error in allocating memory");
        // handle it
    }
}

9 Comments

sizeof *Transform won't compile - maybe you meant sizeof *transform. And sizeof(Transform) would be better as sizeof **transform.
error: invalid application of 'sizeof' to incomplete type 'Transform'|
@SebastianLuke sorry for the mistake. Have updated my answer. Please try again.
@ajay: transform[i] = calloc(1, sizeof **transform); gives me the following error: "dereferencing pointer to incomplete type|"
@ajay Thank you very much! This was the same thing Filipe told me. It was my bad not knowing I can do that in the header.h file. I would vote up you answer too, but I don't have the rep yet. Thank you very much! :)
|

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.