tags:

views:

180

answers:

5

What is the benefit of declaring a C structure member as in array of size 1 instead of a pointer :

struct {
  a_struct_t a_member[1];
  ...
}b_struct;

Thanks in advance

A: 

These are different things.

Such member's name is an address of allocated memory, allocated inside the struct instance itself.

Pavel Radzivilovsky
No, it is not "a pointer to allocated memory". It *is* allocated memory itself. There are no "pointers" there whatsoever.
AndreyT
But as Brian W. Kernighan and Dennis M. Ritchie say in their book "the C programming language":"A structure declaration that is not followed by a list of variables reserves no storage; it merely describes a template or shape of a structure."So I have confusion in this issue of declaration and memory allocation within a struct definition. Can you explain it more. thanks
Walidix
+2  A: 

What you describe are two different things entirely. If you have a pointer as a member:

a_struct_t* a_member;

then it is simply a pointer. There is no memory allocated inside of the struct to hold an a_struct_t. If, on the other hand, you have an array of size 1:

a_struct_t a_member[1];

then your struct actually has an object of type a_struct_t inside of it. From a memory standpoint, it isn't much different from just putting an object of that type inside the struct:

a_struct_t a_member;

From a usage standpoint, an array requires indirection to access the one element (i.e., you need to use *a_member instead of a_member).

James McNellis
But as Brian W. Kernighan and Dennis M. Ritchie say in their book "the C programming language": "A structure declaration that is not followed by a list of variables reserves no storage; it merely describes a template or shape of a structure." So I have confusion in this issue of declaration and memory allocation within a struct definition.
Walidix
@Walidix: That allows you to do `struct thing{ ...};` then later say `struct thing aThing, someThings[thingCount];`. Either way, the interpertation of `struct thing` differs between declaring the member as an array or a pointer.
dmckee
+2  A: 

"Array of size 1 instead of a pointer"? Sorry, but I don't see how this quiestion can possibly make sense. I would understand if you asked about "array of size 1 instead of an ordinary member (non-array)". But "instead of a pointer"? What does pointer have to do with this? How is it interchangeable with an array, to justify the question?

If what you really wanted to ask is why it is declared as an array of size 1 instead of non-array as in

struct { 
  a_struct_t a_member; 
} b_struct; 

then one possible explanation is the well-known idiom called "struct hack". You might see a declaration like

struct { 
  ...
  a_struct_t a_member[1]; 
} b_struct; 

used to implement an array of flexible size as the last member of the struct object. The actual struct object is later created within a memory block that is large enough to accomodate as many array elements as necessary. But in this case the array has to be the last member of the struct, not the first one as in your example.

P.S. From time to time you might see "struct hack" implemented through an array of size 0, which is actually a constraint violation in C (i.e. a compile error).

AndreyT
The struct hack is often used when working with data comm packets, where the "payload" (or "rest of the packet") naturally occurs as the last member in the struct.
Kevin Little
@Kevin Little: And?
AndreyT
@AndreyT: Just giving one concrete example of where a variable-length struct is commonly used. A little real-world context helps explain "the benefit" (to use the OP's words) of the struct hack.
Kevin Little
+4  A: 

In a typical case, a structure with a member that's declared as an array of one item will have that member as the last item in the struct. The intent is that the struct will be allocated dynamically. When it is allocated, the code will allocate space for as many items as you really want/need in that array:

struct X {
    time_t birthday;
    char name[1];
};

struct X *x = malloc(sizeof(*x) + 35);
x->birthday = mktime(&t);
strcpy(x->name, "no more than 35 characters");

This works particularly well for strings -- the character you've allocated in the struct gives you space for the NUL terminator, so when you do the allocation, the number of characters you allocate is exactly the strlen() of the string you're going to put there. For most other kinds of items, you normally want to subtract one from the allocation size (or just live with the allocated space being one item larger than is strictly necessary).

You can do (sort of) the same thing with a pointer, but it results in allocating the body of the struct separately from the item you refer to via the pointer. The good point is that (unlike the method above) more than one item can be allocated dynamically, where the method above only works for the last member of the struct.

Jerry Coffin
The newest C standard allows you do have char name[]; at the end of a struct, and gcc has allowed you do have char name[0]; at the end of a struct for quite a while just for this purpose.
nategoose
A: 

So I think it's been stated that the main difference between pointers and arrays is that you have to allocate memory for pointers.

The tricky part about your question is that even as you allocate space for your struct, if your struct contains a pointer you have to allocate a SECOND time for the pointer, but the pointer itself would be allocated as part of the struct's allocaiton.

If your struct contained an array of 1 you would not have to allocate any additional memory, it would be stored in the struct (which you still have to allocate).

Bill K