1

If you want to allocate an array of struct you can do it statically by declaring something like

struct myStruct myStructArray[100]; 

or dinamically with something like

struct myStruct *myStructArray = calloc(100, sizeof(struct myStruct) );

but in this case you are responsible for freeing the memory.

In many applications and samples I found a mixed approach:

struct wrapperStruct
{
    int myInt;
    struct myStruct myStructArray[1];
};

Then the allocation is performed like this

int n = 100;
size_t memory_size = sizeof(struct wrapperStruct) + (n - 1) * sizeof(struct myStruct);
struct wrapperStruct *wrapperStruct_p = calloc(1, memory_size);

So (if I understood correctly) since the array is the last member of the struct and the field of a struct respect the same position in memory then you are "extending" the single entry array myStructArray with 99 entries. This allow you to safety write something like wrapperStruct_p.myStructArray[44] without causing a buffer overflow and without having to create a dynamic allocated array of struct and then take care of the memory disposal at the end. So the alternative approach would be:

struct wrapperStruct
{
    int myInt;
    struct myStruct *myStructArray;
};

struct wrapperStruct *wrapperStruct_p = calloc(1, sizeof(struct wrapperStruct) );
wrapperStruct_p.myStructArray = calloc(100, sizeof(struct myStruct) )

The question is what happens when you try to free the wrapperStruct_p variable ?

Are you causing a memory leak ?

Is the C memory management able to understand that the array of struct is made of 100 entries and not 1 ?

What are the benefits of the first approach apart from not having to free the pointer inside the struct ?

6
  • One thing I want to note is that the method that uses struct myStruct myStructArray[1]; is effectively faking a flexible array member, in a way that I wouldn't recommend doing (if it's legal at all). This answers "Is the C memory management able to understand that the array of struct is made of 100 entries and not 1?" in part, since using a FAM would make it clear that it's not just 1 element, and the number of elements is stored elsewhere. This is because, in C, the memory manager is the programmer. Commented May 1, 2021 at 11:29
  • To use declare a flexible array member correctly in modern C, use [] instead of [1]. (In GCC, you could use its extension [0]. That should not be used in new code.) If you use [1], the compiler may assume the array has only one element, regardless of how much you allocated, so optimization could transform an expression like p->member[complicated expression] to p->member[0], since zero is the only defined value for the index of an array of one element (so it is a valid optimization to avoid calculating the expression), and that would break your program. Commented May 1, 2021 at 11:31
  • @EricPostpischil I always thought that this expression struct myStruct *myStructArray is equivalent to struct myStruct myStructArray[]. I think you will end up with an uninitiated pointer in both cases. So if you need to allocate both with a calloc or malloc you will have your memory in the heap. Is that correct ? Commented May 2, 2021 at 9:26
  • @Bemipefe: Declaring a member as struct myStruct *myStructArray creates a pointer in the structure. To use it, you allocate memory for the structure, separate allocate memory for the struct myStruct data, and set the pointer to point to that memory. When a member is declared as struct myStruct myStructArray[], it tells the compiler that, when space is allocated for the structure, it may contain extra space for struct myStruct data, and those extra elements will begin at the location in the structure where myStructArray is. Commented May 2, 2021 at 20:55
  • @EricPostpischil Ok thanks. So if I understood correctly the array is stored in the same area of the struct when you use [] in place of *. I'm wondering what happens if you declare a variable like struct wrapperStruct ws;. In this case the struct is stored in the stack and the stack should be expanded to store the array. I'm wondering if a limit can be hit. I mean do I need to allocate struct wrapperStruct *ws so that the struct and the pointer are stored in the heap ? Commented May 3, 2021 at 9:20

1 Answer 1

2

The question is what happens when you try to free the wrapperStruct_p variable ?

Are you causing a memory leak ?

Most likely, but not necessary. The memory for the inner dynamic array is not freed, but you could still free it later if you saved the pointer address to some other variable.

Is the C memory management able to understand that the array of struct is made of 100 entries and not 1 ?

"C memory management" takes care of stack and heap allocations (the latter using systemcalls so maybe it's not really a "C memory management"), it doesn't do much else other than provide syntactic sugar on top of assembler (unlike garbage collected languages like Java or other).

C itself doesn't care about how many entries are somewhere and what part of memory you access (SEGFAULTS are the OS response to memory access violations)

What are the benefits of the first approach apart from not having to free the pointer inside the struct ?

If by "first approach" you mean stack allocated array, then it's mainly the fact that you do not need to allocate anything and the stack does it for you (drawback being that it stays allocated in the declared scope and you can't free up or increase the array space) then the constant allocation speed and assurance you'll get your 100 array items no matter the OS response (many realtime applications require maximum response times, therefore a heap allocation can be a really big slowdown causing problems).

If by "first approach" you mean using the wrapper struct, then I do not see any benefits other than the one you already stated.

I'd even suggest you not advocate/use this approach, since it is a really confusing technique that doesn't serve noticeable benefits (plus it allocates 1 space even though it may not be even used, but that's a detail)

The main goal is to write code that is easily understandable by other people. Machines and compilers can nowadays do wonders with code, so unless you are a compiler designer, standard library developer or machine level programmer for embedded systems, you should write simple to understand code.

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

1 Comment

I like the last sentence. Often code readability and maintainability is not considered much by developers. And things like typedef in C can worsen the problem.

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.