C compare two pointers greater than if one is null - c

If I compare two pointers in C I am aware of C 6.5.8/5 which says:
pointers to structure members declared later compare greater than pointers to members declared earlier in the structure
That is fine but what if one of the pointers is NULL? I know I can do foo != NULL but for example is this against the standard:
char *bar = NULL;
char *foo = "foo";
if(foo > bar) { function(); }
The section doesn't specifically address NULL in the case of greater than which is why I'm confused. Also if you could tell me if it applies to C89 as well as C99.
To clarify, this has nothing to do with structures that is just the part of the standard I was quoting. The code is very similar to what I describe above. I have some pointers to an array and one of those pointers may be null therefore I'd like to know if it's ok to compare using greater than.

Your example is indeed undefined. As explained in C11, 6.5.8., p5, every rule mandates that pointers point to the same object
or one past that object.
So, two pointers may be compared using relational operators: <, >, <=, >=, only if they point to the same object or one past that object. In all other cases:
6.5.8. Relational operators,
. In all other cases, the behavior is undefined.
Pointer with the value NULL, a null pointer, doesn't point to an object. This is explained in:
6.3.2.3 Pointers
If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.

The C99 standard says:
If the objects pointed to are members of the same aggregate object,
pointers to structure members declared later compare greater than pointers to members
declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript
values.
The key here is in same object:
struct {
int a; // structrure members
int b;
} some_struct;
// so pointers to structure members:
&(some_struct.b) > &(some_struct.a)
The same applies for arrays:
char arr[128];
&(arr[100]) > &(arr[1])
If a pointer is NULL then it is most probably not pointing to a member of the same data structure, unless you're programming the BIOS (and even then it's against the standard, since the null pointer is guaranteed to not point inside any object), so the comparison becomes kinda useless

pointers to structure members declared later compare greater than pointers to members declared earlier in the structure
The quote only describes member variables inside a struct. For example:
struct A {
int a;
int b;
};
Then any instance of A has it's address of a smaller than b.
In other words, if someone write a statement like the followings:
A instanceA;
int* aa = &(instanceA.a);
int* ab = &(instanceA.b);
then it is guaranteed that ab > aa as member variable b is defined later than a.

That section of code is talking about:
#include <stdio.h>
struct things {
int blah;
int laterz;
};
struct things t;
int main ( void ) {
int * a = &t.blah;
int * b = &t.laterz;
printf("%p < %p\n", (void *)a, (void *)b);
return 0;
}
A pointer to laterz is greater than one to blah.

The specification also says that you can only compare two related pointers using anything else than equality or inequality.
So if you have two pointers that both point to different places in the same buffer then you can compare them using the greater or lesser than operators., not other wise.
Example
char buffer1[] = "foobar";
char buffer2[] = "some other text";
char *ptr1 = buffer1 + 3;
char *ptr2 = buffer2;
With the above, you can compare buffer1 and ptr1 using < and >. You can't do that with ptr1 and ptr2, only use the == or != operators.

Related

Why can't a defined, fix-sized array be assigned using a compound literal?

Why is it so that a struct can be assigned after defining it using a compound literal (case b) in sample code), while an array cannot (case c))?
I understand that case a) does not work as at that point compiler has no clue of the memory layout on the rhs of the assignment. It could be a cast from any type. But going with this line, in my mind case c) is a perfectly well-defined situation.
typedef struct MyStruct {
int a, b, c;
} MyStruct_t;
void function(void) {
MyStruct_t st;
int arr[3];
// a) Invalid
st = {.a=1, .b=2, .c=3};
// b) Valid since C90
st = (MyStruct_t){.a=1, .b=2, .c=3};
// c) Invalid
arr = (int[3]){[0]=1, [1]=2, [2]=3};
}
Edit:
I am aware that I cannot assign to an array - it's how C's been designed. I could use memcpy or just assign values individually.
After reading the comments and answers below, I guess now my question breaks down to the forever-debated conundrum of why you can't assign to arrays.
What's even more puzzling as suggested by this post and M.M's comment below is that the following assignments are perfectly valid (sure, it breaks strict aliasing rules). You can just wrap an array in a struct and do some nasty casting to mimic an assignable array.
typedef struct Arr3 {
int a[3];
} Arr3_t;
void function(void) {
Arr3_t a;
int arr[3];
a = (Arr3_t){{1, 2, 3}};
*(Arr3_t*)arr = a;
*(Arr3_t*)arr = (Arr3_t){{4, 5, 6}};
}
So then what's stopping developers to include a feature like this to, say C22(?)
C does not have assignment of arrays, at all. That is, where array has any array type, array = /* something here */ is invalid regardless of the contents of "something here". Whether it's a compound literal (which you seem to have confused with designated initializer, a completely different concept) is irrelevant. array1 = array2 would be just as invalid.
As to why it's invalid, at some level that's a question of the motivations/rationale of the C language and its design and unanswerable. However, mechanically, arrays in any context except the operand of sizeof or the operand of & "decay" to pointers to their first element. So in the case of:
arr = (int[3]){[0]=1, [1]=2, [2]=3};
you are attempting to assign pointer to the first element of the compound literal array to a non-lvalue (the rvalue produced when arr decays). And of course that is nonsense.
A compound array literal can be used anywhere that an actual array variable can be used. Since you can't assign one array to another array, it's also not valid to assign a compound literal to an array.
Since you can copy arrays using memcpy(), you could write:
memcpy(arr, (int[3]){[0]=1, [1]=2, [2]=3}, sizeof(arr));
Just like the array variable, the array literal decays to a pointer to its first element.
Compound struct literals can also be used in place of an actual struct variable. But structs can be assign to each other, so it's valid to assign a compound struct literal to a struct variable.
That's the difference between the two cases.

Access an array from the end in C?

I recently noticed that in C, there is an important difference between array and &array for the following declaration:
char array[] = {4, 8, 15, 16, 23, 42};
The former is a pointer to a char while the latter is a pointer to an array of 6 chars. Also it is notable that the writing a[b] is a syntactic sugar for *(a + b). Indeed, you could write 2[array] and it works perfectly according to the standard.
So we could take advantage of this information to write this:
char last_element = (&array)[1][-1];
&array has a size of 6 chars so (&array)[1]) is a pointer to chars located right after the array. By looking at [-1] I am therefore accessing the last element.
With this I could for example swap the entire array :
void swap(char *a, char *b) { *a ^= *b; *b ^= *a; *a ^= *b; }
int main() {
char u[] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < sizeof(u) / 2; i++)
swap(&u[i], &(&u)[1][-i - 1]);
}
Does this method for accessing an array by the end have flaws?
The C standard does not define the behavior of (&array)[1].
Consider &array + 1. This is defined by the C standard, for two reasons:
When doing pointer arithmetic, the result is defined for results from the first element (with index 0) of an array to one beyond the last element.
When doing pointer arithmetic, a pointer to a single object behaves like a pointer to an array with one element. In this case, &array is a pointer to a single object (that is itself an array, but the pointer arithmetic is for the pointer-to-the-array, not a pointer-to-an-element).
So &array + 1 is defined pointer arithmetic that points just beyond the end of array.
However, by definition of the subscript operator, (&array)[1] is *(&array + 1). While the &array + 1 is defined, applying * to it is not. C 2018 6.5.6 8 explicitly tells us, about result of pointer arithmetic, “If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.”
Because of the way most compilers are designed, the code in the question may move data around as you desire. However, this is not a behavior you should rely on. You can obtain a good pointer to just beyond the last element of the array with char *End = array + sizeof array / sizeof *array;. Then you can use End[-1] to refer to the last element, End[-2] to refer to the penultimate element, and so on.
Although the Standard specifies that arrayLvalue[i] means (*((arrayLvalue)+(i))), which would be processed by taking the address of the first element of arrayLvalue, gcc sometimes treats [], when applied to an array-type value or lvalue, as an operator which behaves line an indexed version of .member syntax, yielding a value or lvalue which the compiler will treat as being part of the array type. I don't know if this is ever observable when the array-type operand isn't a member of a struct or union, but the effects are clearly demonstrable in cases where it is, and I know of nothing that would guarantee that similar logic wouldn't be applied to nested arrays.
struct foo {unsigned char x[12]};
int test1(struct foo *p1, struct foo *p2)
{
p1->x[0] = 1;
p2->x[1] = 2;
return p1->x[0];
}
int test2(struct foo *p1, struct foo *p2)
{
char *p;
p1->x[0] = 1;
(&p2->x[0])[1] = 2;
return p1->x[0];
}
The code gcc generates for test1 will always return 1, while the generated code for test2 will return whatever is in p1->x[0]. I am unaware of anything in the Standard or the documentation for gcc that would suggest the two functions should behave differently, nor how one should force a compiler to generate code that would accommodate the case where p1 and p2 happen to identify overlapping parts of an allocated block in the event that should be necessary. Although the optimization used in test1() would be reasonable for the function as written, I know of no documented interpretation of the Standard that would treat that case as UB but define the behavior of the code if it wrote to p2->x[0] instead of p2->x[1].
I would do a for loop where I set i = length of the vector - 1 and each time instead of increasing it, I decrease it until it is greater than 0.
for(int i = vet.length;i>0;i--)

Differences when using ** in C

I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:
int ** arr = NULL;
How can I know if:
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
Isn't it all the same with int ** ?
Another question for the same problem:
If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?
Isn't it all the same with int **?
You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.
The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.
I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).
What I originally wrote refers to code as follows:
void func(int **p_buff)
{
}
//...
int a = 0, *pa = &a;
func(&pa);
//...
int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);
//...
int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
a[i] = malloc(i * sizeof *a[i]);
func(a);
Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.
The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...
Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:
cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]
In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring
void func(int (*a)[10]);
one could use
void func(int a[][10])
to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.
How can I know if :
arr is a pointer to a pointer of an integer
It is always a pointer to pointer to integer.
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
It can never be that. A pointer to an array of pointers to integers would be declared like this:
int* (*arr)[n]
It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and (
with detailed explanation about array pointers) here.
EDIT
Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.
Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.
Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:
int i1=1,i2=2,i3=3,i4=4;
int *p2i = &i1;
int **p2p2i_v1 = &p2i; // pointer to a pointer to a single int
int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int
int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints
// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0]; // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0]; // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0]; // correct; yields 5
// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1]; // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault
// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
How can I know if :
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.
So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.
Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.
Consider these declarations
int a;
int a1[1];
int a2[10];
int *p;
p = &a;
//...
p = a1;
//...
p = a2;
In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.
The type of
int ** arr;
only have one valid interpretation. It is:
arr is a pointer to a pointer to an integer
If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.
Assuming proper initialization, the only guaranteed valid way to use it is:
**arr = 42;
int a = **arr;
However, C allows you to use it in multiple ways.
• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)
int a = **arr;
• arr can be used as a pointer to a pointer to an an array of integer
int a = (*arr)[4];
• arr can be used as a pointer to an array of pointers to integers
int a = *(arr[4]);
• arr can be used as a pointer to an array of pointers to arrays of integers
int a = arr[4][4];
In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.
To know which is valid for the program at hand, you need to look at the code initializing arr.
Update
For the updated part of the question:
If you have:
void foo(char** x) { .... };
the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).
If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.
C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.
In this case arr is a pointer to a pointer to integer.
There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.
One can also create a two dimensional array using it,like this
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++) {
*(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
arr[i]=(int*)malloc(sizeof(int)*col); }
There is one trick when using pointers, read it from right hand side to the left hand side:
int** arr = NULL;
What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.
And int **arr; is the same as int** arr;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/
Visit the site, paste your declaration and it will translate it to English.
For int ** arr;, it says declare arr as pointer to pointer to int.
The site also shows examples. Test yourself on them, then hover your cursor to see the answer.
(double (^)(int , long long ))foo
cast foo into block(int, long long) returning double
int (*(*foo)(void ))[3]
declare foo as pointer to function (void) returning pointer to array 3 of int
It will also translate English into C declarations, which is prety neat - if you get the description correct.

Is the value of a struct variable just an address(like in the case of array)?

In C the following is legal:
int a[] = {27,2};
int *b;
int c;
b = a;
c = *b; /* c == 27 */
The point is that a is just the address of the array so I can assign it to a pointer.
Why is the same not true for struct, I would assume that the value of a struct variable is just the address and therefore I should be able to assign it to a pointer as in:
struct foo bar;
struct foo *doo;
bar.x = 0;
doo = bar; //is this legal?
doo.x = 0; //why can't I use the dot?
In other words if the value of a struct variable is just the address of the first component(and I suppose this is the case like an array) the above code should be legal.
The point is that a is just the address of the array so I can assign it to a pointer.
That's not quite right: compiler converts the name of an array to a pointer that points to the array's initial element. This happens automatically, without requiring a cast or an "address of" operator &. However, a is not just the address, which is evidenced by taking its size with sizeof(a).
This should explain why the same is not true for struct (i.e. because it is not so for arrays). For structs, the "address of" operator & is mandatory:
doo = &bar;
doo.x = 0; //why can't I use the dot?
C has a different syntax for accessing structs elements through a pointer: you need to use the -> operator instead of a dot . operator.
As others have pointed out, the semantics for arrays are different than for structs. As for why that's the case, you have to remember that C was derived from earlier languages (BCPL and B), both of which were "typeless" languages that saw memory as a linear array of fixed-length "words" or "cells". In those older languages, when you declared an array like
auto V[10];
11 memory cells were set aside; one for an object named V, and then 10 more for the array elements; the address of the first element of the array was stored in V.
From Dennis Ritchie's paper The Development of the C Language:
Problems became evident when I tried to extend the type notation, especially to add structured (record) types. Structures, it seemed, should map in an intuitive way onto memory in the machine, but in a structure containing an array, there was no good place to stash the pointer containing the base of the array, nor any convenient way to arrange that it be initialized. For example, the directory entries of early Unix systems might be described in C as
struct {
int inumber;
char name[14];
};
I wanted the structure not merely to characterize an abstract object but also to describe a collection of bits that might be read from a directory. Where could the compiler hide the pointer to name that the semantics demanded? Even if structures were thought of more abstractly, and the space for pointers could be hidden somehow, how could I handle the technical problem of properly initializing these pointers when allocating a complicated object, perhaps one that specified structures containing arrays containing structures to arbitrary depth?
The solution constituted the crucial jump in the evolutionary chain between typeless BCPL and typed C. It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today's C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.
Emphasis mine. This is why array expressions in C are treated differently from all other expression types, including struct types.
doo = bar; //is this legal?
No, Try:
doo = & bar;
^^
doo.x = 0; //why can't I use the dot?
Because doo is a pointer. Try:
doo->x = 0;
^^
doo = bar; //is this legal?
No, it is not valid. The left operand is of a structure type and the right operand is of a pointer type.
This is legal:
doo = &bar;
&bar is of type pointer to struct foo.
Now:
doo.x = 0; //why can't I use the dot?
because the operand has to be of a structure type but it is of a pointer type. Use -> to access elements from an object of pointer to structure type.
doo->x = 0; // this is valid
No, the value of a struct is the struct itself, not its address. This allows you to do something like this:
struct foo a;
struct foo b;
b = a; /* this does a memberwise copy of all fields from a to b */
If you want the address of the struct, use the & operator:
struct foo a;
struct foo* b = &a
struct foo c;
c = *b; /* this does a memberwise copy of all fields from a to c */
No, it's not. What you want to do is:
doo = &bar;
doo->x = 0;
In case of arrays it works because an array of T is implicitly convertible to T*, but this is not the case for structs. A pointer may store the address of your struct objext (&bar). In order to access struct elements indirectly with a pointer one should use the -> operator. a->b is equivalent to (*a).b

Access structure members with a pointer

In C, I am having a structure like this
typedef struct
{
char *msg1;
char *msg2;
.
.
char *msgN;
}some_struct;
some_struct struct1;
some_struct *pstruct1 = &struct1;
I want to keep a pointer or a varible which when incremented or decremented, gives the next/last member variable of this structure. I do not want to use array of char * since it is already designed like this.
I tried using the union and structure combination, but I don't know how to write code for that.
Thought iterator may help but this is C.
Any suggestions ?
You can't do that, safely. You can take a chance that the adjacent character pointers are really adjacent (with no padding) as if they were in an array, but you can't be sure so that's pretty much straight into the undefined behavior minefield.
You can abstract it to an index, and do something like:
char * get_pointer(some_struct *p, int index)
{
if(index == 0)
return p->msg1;
if(index == 1)
return p->msg2;
/* and so on */
return NULL;
}
Then you get to work with an index which you can increment/decrement freely, and just call get_pointer() to map it to a message pointer when needed.
You can do this using strict C, but you need to take certain precautions to ensure compliance with the standard. I will explain these below, but the precautions you need to take are:
(0) Ensure there is no padding by including this declaration:
extern int CompileTimeAssert[
sizeof(some_struct) == NumberOfMembers * sizeof(char *) ? 1 : -1];
(1) Initialize the pointer from the address of the structure, not the address of a member:
char **p = (char **) (char *) &struct1;
(I suspect the above is not necessary, but I would have to insert more reasoning from the C standard.)
(2) Increment the pointer in the following way, instead of using ++ or adding one:
p = (char **) ((char *) p + sizeof(char *));
Here are explanations.
The declaration in (0) acts as a compile-time assertion. If there is no padding in the struct, then the size of the struct equals the number of members multiplied by the size of a member. Then the ternary operator evaluates to 1, the declaration is valid, and the compiler proceeds. If there is padding, the sizes are not equal, the ternary operator evaluates to -1, and the declaration is invalid because an array cannot have a negative size. Then the compiler reports an error and terminates.
Thus, a program containing this declaration will compile only if the struct does not have padding. Additionally, the declaration will not consume any space (it only declares an array that is never defined), and it may be repeated with other expressions (that evaluate to an array size of 1 if their condition is true), so different assertions may be tested with the same array name.
Items (1) and (2) deal with the problem that pointer arithmetic is normally guaranteed to work only within arrays (including a notional sentinel element at the end) (per C 2011 6.5.6 8). However, the C standard makes special guarantees for character types, in C 2011 6.3.2.3 7. A pointer to the struct may be converted to a pointer to a character type, and it will yield a pointer to the lowest addressed byte of the struct. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
In (1), we know from C 2011 6.3.2.3 7, that (char *) &struct1 is a pointer to the first byte of struct1. When converted to (char **), it must be a pointer to the first member of struct1 (in particular thanks to C 2011 6.5.9 6, which guarantees that equal pointers point to the same object, even if they have different types).
Finally, (2) works around the fact that array arithmetic is not directly guaranteed to work on our pointer. That is, p++ would be incrementing a pointer that is not strictly in an array, so the arithmetic is not guaranteed by 6.5.6 8. So we convert it to a char *, for which increments are guaranteed to work by 6.3.2.3 7, we increment it four times, and we convert it back to char **. This must yield a pointer to the next member, since there is no padding.
One might claim that adding the size of char ** (say 4) is not the same as four increments of one char, but certainly the intent of the standard is to allow one to address the bytes of an object in a reasonable way. However, if you want to avoid even this criticism, you can change + sizeof(char *) to be +1+1+1+1 (on implementations where the size is 4) or +1+1+1+1+1+1+1+1 (where it is 8).
Take the address of the first member and store it to char **:
char **first = &struct1.msg1;
char **last = &struct1.msg1 + sizeof(some_struct) / sizeof(char *) - 1;
char **ptr = first; /* *ptr is struct.msg1 */
++ptr; /* now *ptr is struct1.msg2 */
This assumes that the structure only contains char * members.

Resources