59

I have looked around but have been unable to find a solution to what must 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 is the error gcc gives me: error: invalid use of flexible array member

I can get it to compile if i declare the declaration of s inside the struct to be

char* s

and this is probably a superior implementation (pointer arithmetic is faster than arrays, yes?) but I thought in c a declaration of

char s[]

is the same as

char* s
1
  • 8
    char s[] is the same as char *s only inside a function's parameter list. Commented Jan 13, 2010 at 23:16

9 Answers 9

89

The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". The reason you're getting an error (probably anyway) is that it needs to 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 struct 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 member is an array of char, and sizeof(char)==1, so you don't need to multiply by its size, but just like any other malloc you'd need to if it was an array of some other 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 the member to a pointer. In that case, you (normally) need two separate allocations, one for the struct itself, and one for the "extra" data to be pointed to by the pointer. Using a flexible array member you can allocate all the data in a single block.

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

3 Comments

C99 actually allowed that - urghh!
Wow, I've never seen this... does this rely on the "flexible array member" being the last thing declared field in the struct? Are you restricted to only have a single "flexible array member" per struct?
@vicatcu:yes, to both your questions. If memory serves, if you embed a struct containing a flexible array member, it must be the last member in the outer struct, so the flexible array member is always the last item when they're all put together.
28

You need to decide what it is you are trying to do first.


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

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

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

struct my_struct ms;

and then allocate the memory for the array independently

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

In fact, there's no general need to allocate the array memory dynamically

struct my_struct ms;
char s[50];

ms.s = s;

It all depends on what kind of lifetime you need from these objects. If your struct is automatic, then in most cases the array would also be automatic. If the struct object owns the array memory, there's simply no point in doing otherwise. If the struct itself is dynamic, then the array should also normally be dynamic.

Note that in this case you have two independent memory blocks: the struct and the array.


A completely different approach would be to use the "struct hack" idiom. In this case the array becomes an integral part of the struct. Both reside in a single block of memory. In C99 the struct would be declared as

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

and to create an object you'd have to allocate the whole thing dynamically

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

The size of memory block in this case is calculated to accommodate the struct members and the trailing array of run-time size.

Note that in this case you have no option to create such struct objects as static or automatic objects. Structs with flexible array members at the end can only be allocated dynamically in C.


Your assumption about pointer aritmetics being faster then arrays is absolutely incorrect. Arrays work through pointer arithmetics by definition, so they are basically the same. Moreover, a genuine array (not decayed to a pointer) is generally a bit faster than a pointer object. Pointer value has to be read from memory, while the array's location in memory is "known" (or "calculated") from the array object itself.

1 Comment

UV for sizeof *ms + 50 * sizeof *ms->s: easier to review and maintain.
1

The use of an array of unspecified size is only allowed at the end of a structure, and only works in some compilers. It is a non-standard compiler extension. (Although I think I remember C++0x will be allowing this.)

The array will not be a separate allocation for from the structure though. So you need to allocate all of my_struct, not just the array part.

What I do is simply give the array a small but non-zero size. Usually 4 for character arrays and 2 for wchar_t arrays to preserve 32 bit alignment.

Then you can take the declared size of the array into account, when you do the allocating. I often don't on the theory that the slop is smaller than the granularity that the heap manager works in in any case.

Also, I think you should not be using sizeof(char*) in your allocation.

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

Comments

1

I suspect the compiler doesn't know how much space it will need to allocate for s[], should you choose to declare an automatic variable with it.

I concur with what Ben said, declare your struct

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

Also, to clarify his comment about storage, declaring char *s won't put the struct on the stack (since it is dynamically allocated) and allocate s in the heap, what it will do is interpret the first sizeof(char *) bytes of your array as a pointer, so you won't be operating on the data you think you are, and probably will be fatal.

It is vital to remember that although the operations on pointers and arrays may be implemented the same way, they are not the same thing.

Comments

0

Arrays will resolve to pointers, and here you must define s as char *s. The struct basically is a container, and must (IIRC) be fixed size, so having a dynamically sized array inside of it simply isn't possible. Since you're mallocing the memory anyway, this shouldn't make any difference in what you're after.

Basically you're saying, s will indicate a memory location. Note that you can still access this later using notation like s[0].

Comments

0

pointer arithmetic is faster than arrays, yes?

Not at all - they're actually the same. arrays translate to pointer arithmetics at compile-time.

char test[100];
test[40] = 12;

// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;

Comments

0

Working code of storing array inside a structure in a c, and how to store value in the array elements Please leave comment if you have any doubts, i will clarify at my best

Structure Define:

struct process{
    int process_id;
    int tau;
    double alpha;
    int* process_time;
};

Memory Allocation for process structure:

 struct process* process_mem_aloc = (struct process*) malloc(temp_number_of_process * sizeof(struct process));

Looping through multiple process and for each process updating process_time dyanamic array

int process_count = 0;
int tick_count = 0;


while(process_count < number_of_process){


  //Memory allocation for each array of the process, will be containting size equal to number_of_ticks: can hold any value

        (process_mem_aloc + process_count)->process_time = (int*) malloc(number_of_ticks* sizeof(int));

reading data from line by line from a file, storing into process_time array and then printing it from the stored value, next while loop is inside the process while loop

        while(tick_count < number_of_ticks){

            fgets(line, LINE_LENGTH, file);
            *((process_mem_aloc + process_count)->process_time + tick_count) = convertToInteger(line);;
            printf("tick_count : %d , number_of_ticks %d\n",tick_count,*((process_mem_aloc + process_count)->process_time + tick_count));
            tick_count++;
        }

        tick_count = 0;

Comments

0

I see answers mentioning flexible array members (>=C99) or the "struct hack" (C89/90), but as Chris Young helpfully points out in a similar question, this is technically undefined behavior, as you would be accessing memory beyond the bounds of an array. More specifically, pointer arithmetic on an array up to one past the last element is guaranteed not to overflow, but otherwise the behavior is undefined. You could probably get around this by taking advantage of pointer decay. Since pointer arithmetic is well-defined for pointers, I would think the following is well-defined:

struct foo {
    int  length;
    char array[1];
};

struct foo *make_a_thing(char const *src, size_t srclen) {
    struct foo *myfoo = malloc(sizeof *myfoo + (srclen - 1));

    if (myfoo == NULL)
        return NULL;

    memcpy(myfoo->array, src, srclen);
    // memcpy does arithmetic on a `void *` holding the address stored at myfoo->array
    myfoo->length = srclen;
    return myfoo;
}

That said, filtering all interaction with the array through a separate pointer seems like it would get silly in places, and could result in someone else removing the intermediary pointer at some point in the future, which would be bad. It's also true that I could be wrong about that pointer decay comment, as much as I doubt that's the case.

I also see answers mentioning using a pointer and allocating separately. What I have not seen, however, is a combination of the two techniques. I think the following code is completely reasonable:

struct foo {
    int    length;
    char * array;
};

struct foo *make_a_thing(char const *src, size_t srclen) {
    struct foo *myfoo;
    size_t myfoo_size = sizeof *myfoo + srclen;

    if ((myfoo = malloc(myfoo_size)) == NULL)
        return NULL;

    *myfoo = (struct foo){srclen, (void *)myfoo + myfoo_size};
    memcpy(myfoo->array, src, srclen);
    return myfoo;
}

Because they're re-assignable pointers, you can use multiple of them, and there is no requirement for it to be at the end of the struct. You also don't have to worry about that pesky little detail about undefined behavior, since memory returned by malloc is known to be contiguous and the array pointer is therefore valid. There will always be a sizeof (void *) cost to store the pointer, but that's perfectly reasonable.

I would say I moreso fancy this way.

Comments

-8

the code generated will be identical (array and ptr). Apart from the fact that the array one wont compile that is

and BTW - do it c++ and use vector

4 Comments

Suggesting i use c++ and a vector is in no way a constructive suggestion. You could just say: employ a software engineer to write the program for you
The generated code will not be even remotely identical. Array is not a pointer. Embedding array into a struct or pointing to an array from a struct are two completely different things.
yes u are correct they are not identical. I was trying to say that in cases where code is working on something that has been passed to it as a foo * or a foo [] then the code will be identical. Intrinsically there is no perf difference
Tom, some people are not aware of STL, c++ vector, etc. I was trying to post a little out of the box. I am sorry if u felt this was not helpful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.