AbhinavChoudhury
AbhinavChoudhury

Reputation: 1197

Difference between use of pointer and array with zero elements in structs

How do the two implementations differ:

struct queue {
    int a;
    int b;
    q_info *array;
};

and

struct queue {
    int a;
    int b;
    q_info array[0];
};

Upvotes: 4

Views: 2124

Answers (5)

Hrishi
Hrishi

Reputation: 7138

q_info array[0];

decays to a pointer because of the automatic conversion. However, it is not assignable. You cannot say

array = <some address of an object>;

afterwards.

Upvotes: 1

ams
ams

Reputation: 25599

These are completely different things:

  • The first contains a pointer to an external array.
  • the second is an inline array that happens to have zero elements.

The reason people do this is it's more space-efficient. You simply over-allocate the memory the struct needs, and then pretend the array has more elements then declared - the compiler won't mind (usually).

It also means you have one less pointer to dereference through, and you can allocate and free the memory for the struct and the array all in one.

Obviously, this trick only works when the array is the last element in the struct.

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409482

For the zero-sized array member, you can, when you allocate the structure, allocate more memory than the size of struct queue (for example malloc(sizeof(struct queue) + sizeof(q_info) * 10)) to have a contiguous area of memory you can use. Then the array will be part of that memory allocated, and for the example allocation you have ten q_info entries in it.

For the pointer, you have to make two allocations, one for the queue structure, and one for the array member. You of course have to call free twice, once for the array pointer and once for the structure.

However, once allocated both can be used the same.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727137

The second struct does not use an array of zero elements - this is a pre-C99 trick for making flexible array members. The difference is that in the first snippet you need two mallocs - one for the struct, and one for the array, while in the second one you can do both in a single malloc:

size_t num_entries = 100;
struct queue *myQueue = malloc(sizeof(struct queue)+sizeof(q_info)*num_entries);

instead of

size_t num_entries = 100;
struct queue *myQueue = malloc(sizeof(struct queue));
myQueue->array = malloc(sizeof(q_info)*num_entries);

This lets you save on the number of deallocations, provides better locality of references, and also saves the space for one pointer.

Starting with C99 you can drop zero from the declaration of the array member:

struct queue {
    int a;
    int b;
    q_info array[];
};

Upvotes: 11

starrify
starrify

Reputation: 14781

In the first one there is actually a pointer allocated in struct queue, and sizeof(struct queue) == 2 * sizeof(int) + sizeof(q_info*)

In the second one there is no pointer or anything named array really exists in struct queue, and sizeof(struct queue) == 2 * sizeof(int). This is known as a trick to conveniently reference the data before or later using array. I've used this trick in implementing a memory allocator.

Upvotes: 1

Related Questions