How to enable dynamic array INSIDE a struct in C?

I looked around, but could not find a solution to what should be a well-asked question. Here is the code I have:

#include <stdlib.h> struct my_struct { int n; char s[] }; int main() { struct my_struct ms; ms.s = malloc(sizeof(char*)*50); } 

and here the gcc error gives me: error: invalid use of a flexible array element

I can get it to compile if I declare an s declaration inside the structure

 char* s 

and this is probably an excellent implementation (pointer arithmetic is faster than arrays, yes?) but I thought in the c declaration

 char s[] 

coincides with

 char* s 
+34
c memory-management arrays pointers struct
Jan 13 '10 at 23:02
source share
8 answers

The way you wrote it used to be called a "structure hulk" until C99 blessed it as a "flexible array element." The reason you get the error (probably one way or another) is because it should be followed by a semicolon:

 #include <stdlib.h> struct my_struct { int n; char s[]; }; 

When you allocate space for this, you want to allocate the size of the structure plus the amount of space you want for the array:

 struct my_struct *s = malloc(sizeof(struct my_struct) + 50); 

In this case, the flexible array element is an array of char and sizeof (char) == 1, so you do not need to multiply its size, but like any other malloc, d is needed if it was an array of a different type:

 struct dyn_array { int size; int data[]; }; struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int)); 

Edit: This gives a different result from changing a member to a pointer. In this case, you (usually) need two separate distributions: one for the structure itself and one for the "extra" data that the pointer points to. Using the flexible member of the array, you can select all the data in one block.

+56
Jan 13 '10 at 23:14
source share

You need to decide what exactly you are trying to do first.




If you want to have a structure with a pointer to an [independent] array inside, you must declare it as

 struct my_struct { int n; char *s; }; 

In this case, you can create the actual structure object in any way (for example, as an automatic variable)

 struct my_struct ms; 

and then allocate memory for the array independently

 ms.s = malloc(50 * sizeof *ms.s); 

There is really no general need to dynamically allocate array memory

 struct my_struct ms; char s[50]; ms.s = s; 

It all depends on what time of life you need from these objects. If your structure is automatic, then in most cases the array will also be automatic. If the struct object owns the memory of the array, there is simply no point in doing it otherwise. If the structure itself is dynamic, then the array must also be dynamic.

Please note that in this case you have two independent memory blocks: structure and array.




A completely different approach is to use the "struct hack" idiom. In this case, the array becomes an integral part of the structure. Both are in the same memory block. In C99, the structure will be declared as

 struct my_struct { int n; char s[]; }; 

and create an object that you will need to dynamically highlight it all

 struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s); 

The size of the memory block in this case is calculated to accommodate the elements of the structure and the final array of execution time.

Note that in this case, you cannot create structure objects such as static or automatic objects. Structures with flexible array elements at the end can only be dynamically allocated in C.




Your assumption that pointer arithmetic is faster than arrays is completely wrong. Arrays work by arithmetic pointer by definition, so they are basically the same. Moreover, a genuine array (not decaying into a pointer) is usually a little faster than a pointer object. The pointer value must be read from memory, and the location of the array in memory is โ€œknownโ€ (or โ€œcalculatedโ€) from the array itself.

+16
Jan 13 '10 at 23:27
source share

Arrays will allow pointers, and here you must define s as char *s . The structure is basically a container and should (IIRC) be a fixed size, so having a dynamic-sized array inside it is simply not possible. Since you are still malloc with memory, this should not make any difference in what you need.

Basically you say s will indicate the memory location. Note that you can access this later using a notation of type s[0] .

0
Jan 13 '10 at 23:05
source share

Pointer arithmetic is faster than arrays, right?

Not at all - they are actually the same. arrays translate to pointer arithmetic at compile time.

 char test[100]; test[40] = 12; // translates to: (test now indicates the starting address of the array) *(test+40) = 12; 
0
Jan 13 '10 at 23:06
source share

An array of indefinite size is allowed only at the end of the structure and works only on some compilers. This is a non-standard compiler extension. (Although I think I remember that C ++ 0x will allow this.)

However, the array will not be a separate distribution from the structure. Therefore, you need to select all my_struct , and not just part of the array.

What I'm doing is just give the array a small but nonzero size. Usually 4 for character arrays and 2 for wchar_t arrays to preserve 32-bit alignment.

You can then take the declared size of the array into account when allocating. I often do not rely on the theory that slop is less than the granularity with which the heap manager works anyway.

Also, I think you should not use sizeof (char *) in your distribution.

This is what I would do.

 struct my_struct { int nAllocated; char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator }; int main() { struct my_struct * pms; int cb = sizeof(*pms) + sizeof(pms->s[0])*50; pms = (struct my_struct*) malloc(cb); pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]); } 
0
Jan 13 '10 at 23:20
source share

I suspect that the compiler does not know how much space it will need to allocate for s [] if you decide to declare an automatic variable with it.

I agree with what Ben said when announcing your structure

 struct my_struct { int n; char s[1]; }; 

Also, to clarify his comment about storage, the char *s declaration will not push the structure onto the stack (since it is dynamically allocated) and allocate s on the heap, what it will do is interpret the first sizeof(char *) bytes of your array as a pointer, so you wonโ€™t work with data that you think is and is likely to be fatal.

It is important to remember that although operations with pointers and arrays can be implemented the same way, they are not the same thing.

0
Jan 13 '10 at 23:50
source share

There are many answers regarding the flexible array of C99.

I would like to comment on the answer of Alexander Gessler regarding pointers that match arrays.

This is not true; Arrays are an expression, pointers are a variable.

They have subtle differences, especially when crossing LARGE data volumes. Sometimes you need to squeeze every mSec (I work on embedded graphics systems).

0
Nov 16 '11 at 19:20
source share

the generated code will be identical (array and ptr). Besides the fact that the array will not compile, it

and BTW - do it C ++ and use a vector

-6
Jan 13 '10 at 23:07
source share



All Articles