is it possible to have a union of arrays in c - c

I wish to have a type which can be used as two different array structures - depending on context. They are not to be used interchangeably whilst the program is executing, rather when the program is executed with a particular start-up flag the type will be addressed as one of the array types
(for example):
array1[2][100]
or
array2[200];
I am not interested in how the data is organised (well I am but it is not relevant to what I wish to achieve)
union m_arrays
{
uint16_t array1[2][100];
uint16_t array2[200];
};
or do I have to use a pointer and alloc it at runtime?
uint16_t * array;
array = malloc(200 * sizeof(uint16_t));
uint16_t m_value =100;
*(array + 199) = m_value;
//equivalent uint16_t array1[1][99] == *(array + 199);
//equivalent uint16_t array2[199] == *(array + 199);
I haven't tried anything as yet

A union as itself contains either of its members. That is, only one member can be "bound" at a time (this is just an abstraction, since C has no notion about which member is "active").
In general, the effective size of that union will be the higher size on bytes of its members.
Let me give an example:
#include <stdio.h>
typedef union m_arrays
{
int array1[2][100];
int array2[400];
} a;
int main()
{
printf("%zu", sizeof(a));
return 0;
}
In this example, this would print 1600 (assuming int is 4 bytes long, but at the end it will depend on the architecture) and is the highest size in bytes. So, YES, you can have a union of arrays in C

Yes, this does work, and it's actually precisely because of how arrays are different from pointers. I'm sure you've heard that arrays in C are really just pointers, but the truth is that there are some important differences.
First, an array always points to somewhere on the stack. You can't use malloc to make an array because malloc returns a heap address. A pointer can point anywhere, you can even set it to an arbitrary integer if you want (though there's no guaruntee you can access that memory that it points to).
Second, because arrays are fixed length, the compiler can and does allocate them for you when you declare them. Importantly, this comes with the guaruntee that the whole array is in one continuous memory block. So if you declare int arr[2][100], you'll have 200 int slots allocated in a row on the stack. That means you can treat any multimensional array as a single-dimensional array if you want to, e.g. instead of arr[y][x] you could do arr[0][y*100+x]. You could also do something like int* arr2 = arr and then treat arr2 as a regular array even though arr is technically an int** (you'll get a warning for doing either of these things, my point is that you can do them because of how arrays are made).
The third, and probably most important difference, is a consequence of the second. When you have an array in a struct or union, the struct/union isn't just holding a pointer to the first element. It holds the entire array. This is often used for copying arrays or returning them from functions. What this means for you is that what you want to do works despite what someone who's heard that arrays are pointers might initially think. If arrays were just an address and they were initialized by allocating at that address, there would be two different arrays initialized at two different places, and having the pointers to them in a union would mean one gets overwritten and now you have an array somewhere that you can't access.
So when this all comes together, your union of arrays basically has one array with two different ways of accessing the data (which is what you want if I'm not mistaken). A little example:
#include <stdio.h>
int main(void) {
union {
int arr1[4];
int arr2[2][2];
} u;
u.arr1[0] = 1;
u.arr1[1] = 2;
u.arr1[2] = 3;
u.arr1[3] = 4;
printf("%d %d\n%d %d\n", u.arr2[0][0], u.arr2[0][1], u.arr2[1][0], u.arr2[1][1]);
return 0;
}
Output:
1 2
3 4
We can also quickly walk through why this wouldn't work with pure pointers. Let's say we instead had a union like this:
union {
int* arr1;
int** arr2;
} u;
Then we might initialize with u.arr1 = (int*) malloc(4 * sizeof (int));. Then we could use arr1 like a normal array. But what happens when we try to use arr2? Well, arr2[y][x] is of course syntactic sugar for *(*(arr2+y)+x)). Once it's dereferenced that first time, we now have an int, since the address points to an int. So when we add x to that int and try to dereference again, we're trying to dereference an int. C will try to do it, and if you're very unlucky it will succeed; I say unlucky because then you'll be messing with arbitrary memory. What's more likely is a segfault because whatever int is there is most likely not an address your program has access to.

Related

How to dynamically array of pointers specifying two dimensions at run time with a single malloc() call [duplicate]

I am writing C code and I would like to heap allocate 512*256 bytes. For my own convenience I would like to be able to access the elements with the syntax array[a][b]; no arithmetic to find the right index.
Every tutorial I see online tells me to create an array of pointers that point to arrays of the rows I want in my array. This means that each subarray needs to be malloc'd and free'd individually. I am interested in a solution that only requires one call to malloc and one call to free.(Thus all elements are contiguous) I think this is possible because I will not be constructing a jagged array.
I would appreciate if anyone could share the syntax for declaring such an array.
Well, if you want to allocate array of type, you assign it into a pointer of that type.
Since 2D arrays are arrays of arrays (in your case, an array of 512 arrays of 256 chars), you should assign it into a pointer to array of 256 chars:
char (*arr)[256]=malloc(512*256);
//Now, you can, for example:
arr[500][200]=75;
(The parentheses around *arr are to make it a pointer to array, and not an array of pointers)
If you allocate the array like this, it requires two calls to free, but it allows array[a][b] style syntax and is contiguous.
char **array = malloc(512 * sizeof(char *));
array[0] = malloc(512*256);
for (int i = 1; i < 512; i++)
array[i] = array[0] + (256 * i);
See array2 here for more information: http://c-faq.com/aryptr/dynmuldimary.html
This is easy assuming you don't need compatibility with the ancient C89 standard (among current C compilers, only MSVC and a few embedded-target compilers are that backwards). Here's how you do it:
int (*array)[cols] = malloc(rows * sizeof *array);
Then array[a][b] is valid for any a in [0,rows) and b in [0,cols).
In the language of the C standard, array has variably-modified type. If you want to pass the pointer to other functions, you'll need to repeat this type in the function argument list and make sure that at least the number of columns is passed to the function (since it's needed as part of the variably-modified type).
Edit: I missed the fact that OP only cares about a fixed size, 512x256. In that case, C89 will suffice, and all you need is:
int (*array)[256] = malloc(512 * sizeof *array);
The exact same type can be used in function argument lists if you need to pass the pointer around between functions (and also as a function return type, but for this use you might want to typedef it... :-)
Since you know the size of the array ahead of time, you could create a struct type that contains a 521x256 array, and then dynamically allocate the struct.
It is possible to dynamically allocate the same kind of multidimensional array that
static char x[512][256];
gives you, but it's a wee tricky because of type decay. I only know how to do it with a typedef:
typedef char row[512];
row *x = malloc(sizeof(row) * 256);
This only lets you determine the size of the second dimension at runtime. If both dimensions can vary at runtime, you need a dope vector.
If you know the size of the array, you can typedef it, and make a pointer to it. Here is a short snippet that demonstrates this use:
#include <stdio.h>
#include <stdlib.h>
typedef int array2d[20][20];
int main() {
int i,j;
array2d *a = malloc(sizeof(array2d));
for(i=0;i!=20;i++)
for(j=0;j!=20;j++)
(*a)[i][j] = i + j;
for(i=0;i!=20;i++)
for(j=0;j!=20;j++)
printf("%d ",(*a)[i][j]);
free(a);
return 0;
}
All great answers. I just have one thing to add for old weirdos like me who enjoy "retro" coding 16 bit with old compilers like Turbo C, on old machines. Variable length arrays are wonderful, but not needed.
char (*array)[81];
int lineCount;
/* Go get your lineCount.*/
lineCount = GetFileLines("text.fil");
array = malloc(lineCount * 81);
This is how we did "VLA" back in the olden days. It works exactly the same as
char (*array)[81] = malloc(lineCount * 81); /* error pre C99 */
without the luxury of VLA.
Just my old and tarnished 2 cents.

Why do we use zero length array instead of pointers?

It's said that zero length array is for variable length structure, which I can understand. But what puzzle me is why we don't simply use a pointer, we can dereference and allocate a different size structure in the same way.
EDIT - Added example from comments
Assuming:
struct p
{
char ch;
int *arr;
};
We can use this:
struct p *p = malloc(sizeof(*p) + (sizeof(int) * n));
p->arr = (struct p*)(p + 1);
To get a contiguous chunk of memory. However, I seemed to forget the space p->arr occupies and it seems to be a disparate thing from the zero size array method.
If you use a pointer, the structure would no longer be of variable length: it will have fixed length, but its data will be stored in a different place.
The idea behind zero-length arrays* is to store the data of the array "in line" with the rest of the data in the structure, so that the array's data follows the structure's data in memory. Pointer to a separately allocated region of memory does not let you do that.
* Such arrays are also known as flexible arrays; in C99 you declare them as element_type flexArray[] instead of element_type flexArray[0], i.e. you drop zero.
The pointer isn't really needed, so it costs space for no benefit. Also, it might imply another level of indirection, which also isn't really needed.
Compare these example declarations, for a dynamic integer array:
typedef struct {
size_t length;
int data[0];
} IntArray1;
and:
typedef struct {
size_t length;
int *data;
} IntArray2;
Basically, the pointer expresses "the first element of the array is at this address, which can be anything" which is more generic than is typically needed. The desired model is "the first element of the array is right here, but I don't know how large the array is".
Of course, the second form makes it possible to grow the array without risking that the "base" address (the address of the IntArray2 structure itself) changes, which can be really neat. You can't do that with IntArray1, since you need to allocate the base structure and the integer data elements together. Trade-offs, trade-offs ...
These are various forms of the so-called "struct hack", discussed in question 2.6 of the comp.lang.c FAQ.
Defining an array of size 0 is actually illegal in C, and has been at least since the 1989 ANSI standard. Some compilers permit it as an extension, but relying on that leads to non-portable code.
A more portable way to implement this is to use an array of length 1, for example:
struct foo {
size_t len;
char str[1];
};
You could allocate more than sizeof (struct foo) bytes, using len to keep track of the allocated size, and then access str[N] to get the Nth element of the array. Since C compilers typically don't do array bounds checking, this would generally "work". But, strictly speaking, the behavior is undefined.
The 1999 ISO standard added a feature called "flexible array members", intended to replace this usage:
struct foo {
size_t len;
char str[];
};
You can deal with these in the same way as the older struct hack, but the behavior is well defined. But you have to do all the bookkeeping yourself; sizeof (struct foo) still doesn't include the size of the array, for example.
You can, of course, use a pointer instead:
struct bar {
size_t len;
char *ptr;
};
And this is a perfectly good approach, but it has different semantics. The main advantage of the "struct hack", or of flexible array members, is that the array is allocated contiguously with the rest of the structure, and you can copy the array along with the structure using memcpy (as long as the target has been properly allocated). With a pointer, the array is allocated separately -- which may or may not be exactly what you want.
This is because with a pointer you need a separate allocation and assignment.
struct WithPointer
{
int someOtherField;
...
int* array;
};
struct WithArray
{
int someOtherField;
...
int array[1];
};
To get an 'object' of WithPointer you need to do:
struct WithPointer* withPointer = malloc(sizeof(struct WithPointer));
withPointer.array = malloc(ARRAY_SIZE * sizeof(int));
To get an 'object' of WithArray:
struct WithArray* withArray = malloc(sizeof(struct WithArray) +
(ARRAY_SIZE - 1) * sizeof(int));
That's it.
In some cases it's also very handy, or even necessary, to have the array in consecutive memory; for example in network protocol packets.

Pointer to 2D arrays in C

I know there is several questions about that which gives good (and working) solutions, but none IMHO which says clearly what is the best way to achieve this.
So, suppose we have some 2D array :
int tab1[100][280];
We want to make a pointer that points to this 2D array.
To achieve this, we can do :
int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use
or, alternatively :
int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use
OK, both seems to work well. Now I would like to know :
what is the best way, the 1st or the 2nd ?
are both equals for the compiler ? (speed, perf...)
is one of these solutions eating more memory than the other ?
what is the more frequently used by developers ?
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
Using pointer2 or pointer3 produce the same binary except manipulations as ++pointer2 as pointed out by WhozCraig.
I recommend using typedef (producing same binary code as above pointer3)
typedef int myType[100][280];
myType *pointer3;
Note: Since C++11, you can also use keyword using instead of typedef
using myType = int[100][280];
myType *pointer3;
in your example:
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
Note: If the array tab1 is used within a function body => this array will be placed within the call stack memory. But the stack size is limited. Using arrays bigger than the free memory stack produces a stack overflow crash.
The full snippet is online-compilable at gcc.godbolt.org
int main()
{
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
static_assert( sizeof(pointer1) == 2240, "" );
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
static_assert( sizeof(pointer2) == 8, "" );
static_assert( sizeof(pointer3) == 8, "" );
// Use 'typedef' (or 'using' if you use a modern C++ compiler)
typedef int myType[100][280];
//using myType = int[100][280];
int tab1[100][280];
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
return myint;
}
Both your examples are equivalent. However, the first one is less obvious and more "hacky", while the second one clearly states your intention.
int (*pointer)[280];
pointer = tab1;
pointer points to an 1D array of 280 integers. In your assignment, you actually assign the first row of tab1. This works since you can implicitly cast arrays to pointers (to the first element).
When you are using pointer[5][12], C treats pointer as an array of arrays (pointer[5] is of type int[280]), so there is another implicit cast here (at least semantically).
In your second example, you explicitly create a pointer to a 2D array:
int (*pointer)[100][280];
pointer = &tab1;
The semantics are clearer here: *pointer is a 2D array, so you need to access it using (*pointer)[i][j].
Both solutions use the same amount of memory (1 pointer) and will most likely run equally fast. Under the hood, both pointers will even point to the same memory location (the first element of the tab1 array), and it is possible that your compiler will even generate the same code.
The first solution is "more advanced" since one needs quite a deep understanding on how arrays and pointers work in C to understand what is going on. The second one is more explicit.
int *pointer[280]; //Creates 280 pointers of type int.
In 32 bit os, 4 bytes for each pointer. so 4 * 280 = 1120 bytes.
int (*pointer)[100][280]; // Creates only one pointer which is used to point an array of [100][280] ints.
Here only 4 bytes.
Coming to your question, int (*pointer)[280]; and int (*pointer)[100][280]; are different though it points to same 2D array of [100][280].
Because if int (*pointer)[280]; is incremented, then it will points to next 1D array, but where as int (*pointer)[100][280]; crosses the whole 2D array and points to next byte. Accessing that byte may cause problem if that memory doen't belongs to your process.
Ok, this is actually four different question. I'll address them one by one:
are both equals for the compiler? (speed, perf...)
Yes. The pointer dereferenciation and decay from type int (*)[100][280] to int (*)[280] is always a noop to your CPU. I wouldn't put it past a bad compiler to generate bogus code anyways, but a good optimizing compiler should compile both examples to the exact same code.
is one of these solutions eating more memory than the other?
As a corollary to my first answer, no.
what is the more frequently used by developers?
Definitely the variant without the extra (*pointer) dereferenciation. For C programmers it is second nature to assume that any pointer may actually be a pointer to the first element of an array.
what is the best way, the 1st or the 2nd?
That depends on what you optimize for:
Idiomatic code uses variant 1. The declaration is missing the outer dimension, but all uses are exactly as a C programmer expects them to be.
If you want to make it explicit that you are pointing to an array, you can use variant 2. However, many seasoned C programmers will think that there's a third dimension hidden behind the innermost *. Having no array dimension there will feel weird to most programmers.

Heap allocate a 2D array (not array of pointers)

I am writing C code and I would like to heap allocate 512*256 bytes. For my own convenience I would like to be able to access the elements with the syntax array[a][b]; no arithmetic to find the right index.
Every tutorial I see online tells me to create an array of pointers that point to arrays of the rows I want in my array. This means that each subarray needs to be malloc'd and free'd individually. I am interested in a solution that only requires one call to malloc and one call to free.(Thus all elements are contiguous) I think this is possible because I will not be constructing a jagged array.
I would appreciate if anyone could share the syntax for declaring such an array.
Well, if you want to allocate array of type, you assign it into a pointer of that type.
Since 2D arrays are arrays of arrays (in your case, an array of 512 arrays of 256 chars), you should assign it into a pointer to array of 256 chars:
char (*arr)[256]=malloc(512*256);
//Now, you can, for example:
arr[500][200]=75;
(The parentheses around *arr are to make it a pointer to array, and not an array of pointers)
If you allocate the array like this, it requires two calls to free, but it allows array[a][b] style syntax and is contiguous.
char **array = malloc(512 * sizeof(char *));
array[0] = malloc(512*256);
for (int i = 1; i < 512; i++)
array[i] = array[0] + (256 * i);
See array2 here for more information: http://c-faq.com/aryptr/dynmuldimary.html
This is easy assuming you don't need compatibility with the ancient C89 standard (among current C compilers, only MSVC and a few embedded-target compilers are that backwards). Here's how you do it:
int (*array)[cols] = malloc(rows * sizeof *array);
Then array[a][b] is valid for any a in [0,rows) and b in [0,cols).
In the language of the C standard, array has variably-modified type. If you want to pass the pointer to other functions, you'll need to repeat this type in the function argument list and make sure that at least the number of columns is passed to the function (since it's needed as part of the variably-modified type).
Edit: I missed the fact that OP only cares about a fixed size, 512x256. In that case, C89 will suffice, and all you need is:
int (*array)[256] = malloc(512 * sizeof *array);
The exact same type can be used in function argument lists if you need to pass the pointer around between functions (and also as a function return type, but for this use you might want to typedef it... :-)
Since you know the size of the array ahead of time, you could create a struct type that contains a 521x256 array, and then dynamically allocate the struct.
It is possible to dynamically allocate the same kind of multidimensional array that
static char x[512][256];
gives you, but it's a wee tricky because of type decay. I only know how to do it with a typedef:
typedef char row[512];
row *x = malloc(sizeof(row) * 256);
This only lets you determine the size of the second dimension at runtime. If both dimensions can vary at runtime, you need a dope vector.
If you know the size of the array, you can typedef it, and make a pointer to it. Here is a short snippet that demonstrates this use:
#include <stdio.h>
#include <stdlib.h>
typedef int array2d[20][20];
int main() {
int i,j;
array2d *a = malloc(sizeof(array2d));
for(i=0;i!=20;i++)
for(j=0;j!=20;j++)
(*a)[i][j] = i + j;
for(i=0;i!=20;i++)
for(j=0;j!=20;j++)
printf("%d ",(*a)[i][j]);
free(a);
return 0;
}
All great answers. I just have one thing to add for old weirdos like me who enjoy "retro" coding 16 bit with old compilers like Turbo C, on old machines. Variable length arrays are wonderful, but not needed.
char (*array)[81];
int lineCount;
/* Go get your lineCount.*/
lineCount = GetFileLines("text.fil");
array = malloc(lineCount * 81);
This is how we did "VLA" back in the olden days. It works exactly the same as
char (*array)[81] = malloc(lineCount * 81); /* error pre C99 */
without the luxury of VLA.
Just my old and tarnished 2 cents.

Increasing The Size of Memory Allocated to a Struct via Malloc

I just learned that it's possible to increase the size of the memory you'll allocate to a struct when using the malloc function. For example, you can have a struct like this:
struct test{
char a;
int v[1];
char b;
};
Which clearly has space for only 2 chars and 1 int (pointer to an int in reality, but anyway). But you could call malloc in such a way to make the struct holds 2 chars and as many ints as you wanted (let's say 10):
int main(){
struct test *ptr;
ptr = malloc (sizeof(struct test)+sizeof(int)*9);
ptr->v[9]=50;
printf("%d\n",ptr->v[9]);
return 0;
}
The output here would be "50" printed on the screen, meaning that the array inside the struct was holding up to 10 ints.
My questions for the experienced C programmers out there:
What is happening behind the scenes here? Does the computer allocate 2+4 (2 chars + pointer to int) bytes for the standard "struct test", and then 4*9 more bytes of memory and let the pointer "ptr" put whatever kind of data it wants on those extra bytes?
Does this trick only works when there is an array inside the struct?
If the array is not the last member of the struct, how does the computer manage the memory block allocated?
...Which clearly has space for only 2 chars and 1 int (pointer to an
int in reality, but anyway)...
Already incorrect. Arrays are not pointers. Your struct holds space for 2 chars and 1 int. There's no pointer of any kind there. What you have declared is essentially equivalent to
struct test {
char a;
int v;
char b;
};
There's not much difference between an array of 1 element and an ordinary variable (there's conceptual difference only, i.e. syntactic sugar).
...But you could call malloc in such a way to make it hold 1 char and as
many ints as you wanted (let's say 10)...
Er... If you want it to hold 1 char, why did you declare your struct with 2 chars???
Anyway, in order to implement an array of flexible size as a member of a struct you have to place your array at the very end of the struct.
struct test {
char a;
char b;
int v[1];
};
Then you can allocate memory for your struct with some "extra" memory for the array at the end
struct test *ptr = malloc(offsetof(struct test, v) + sizeof(int) * 10);
(Note how offsetof is used to calculate the proper size).
That way it will work, giving you an array of size 10 and 2 chars in the struct (as declared). It is called "struct hack" and it depends critically on the array being the very last member of the struct.
C99 version of C language introduced dedicated support for "struct hack". In C99 it can be done as
struct test {
char a;
char b;
int v[];
};
...
struct test *ptr = malloc(sizeof(struct test) + sizeof(int) * 10);
What is happening behind the scenes here? Does the computer allocate
2+4 (2 chars + pointer to int) bytes for the standard "struct test",
and then 4*9 more bytes of memory and let the pointer "ptr" put
whatever kind of data it wants on those extra bytes?
malloc allocates as much memory as you ask it to allocate. It is just a single flat block of raw memory. Nothing else happens "behind the scenes". There's no "pointer to int" of any kind in your struct, so any questions that involve "pointer to int" make no sense at all.
Does this trick only works when there is an array inside the struct?
Well, that's the whole point: to access the extra memory as if it belongs to an array declared as the last member of the struct.
If the array is not the last member of the struct, how does the computer manage the memory block allocated?
It doesn't manage anything. If the array is not the last member of the struct, then trying to work with the extra elements of the array will trash the members of the struct that declared after the array. This is pretty useless, which is why the "flexible" array has to be the last member.
No, that does not work. You can't change the immutable size of a struct (which is a compile-time allocation, after all) by using malloc ( ) at run time. But you can allocate a memory block, or change its size, such that it holds more than one struct:
int main(){
struct test *ptr;
ptr = malloc (sizeof(struct test) * 9);
}
That's just about all you can do with malloc ( ) in this context.
In addition to what others have told you (summary: arrays are not pointers, pointers are not arrays, read section 6 of the comp.lang.c FAQ), attempting to access array elements past the last element invokes undefined behavior.
Let's look at an example that doesn't involve dynamic allocation:
struct foo {
int arr1[1];
int arr2[1000];
};
struct foo obj;
The language guarantees that obj.arr1 will be allocated starting at offset 0, and that the offset of obj.arr2 will be sizeof (int) or more (the compiler may insert padding between struct members and after the last member, but not before the first one). So we know that there's enough room in obj for multiple int objects immediately following obj.arr1. That means that if you write obj.arr1[5] = 42, and then later access obj.arr[5], you'll probably get back the value 42 that you stored there (and you'll probably have clobbered obj.arr2[4]).
The C language doesn't require array bounds checking, but it makes the behavior of accessing an array outside its declared bounds undefined. Anything could happen -- including having the code quietly behave just the way you want it to. In fact, C permits array bounds checking; it just doesn't provide a way to handle errors, and most compilers don't implement it.
For an example like this, you're most likely to run into visible problems in the presence of optimization. A compiler (particularly an optimizing compiler) is permitted to assume that your program's behavior is well-defined, and to rearrange the generated code to take advantage of that assumption. If you write
int index = 5;
obj.arr1[index] = 42;
the compiler is permitted to assume that the index operation doesn't go outside the declared bounds of the array. As Henry Spencer wrote, "If you lie to the compiler, it will get its revenge".
Strictly speaking, the struct hack probably involves undefined behavior (which is why C99 added a well-defined version of it), but it's been so widely used that most or all compilers will support it. This is covered in question 2.6 of the comp.lang.c FAQ.

Resources