There are multiple issues with trying to use pointer arithmetic in this matter.
The first issue, as has been mentioned in other answers, is that there could be padding throughout the struct throwing off your calculations.
C11 working draft 6.7.2.1 p15: (bold emphasis mine)
Within a structure object, the non-bit-field members and the units in which bit-fields
reside have addresses that increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.
The second issue is that pointer arithmetic is done in multiples of the size of the type being pointed to. In the case of a struct, if you add 1 to a pointer to a struct, the pointer will be pointing to an object after the struct. Using your example struct Foo
:
Foo x[3];
Foo *y = x+1; // y points to the second Foo (x[1]), not the second byte of x[0]
6.5.6 p8:
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist.
A third issue is that performing pointer-arithmetic such that the result points more than one past the end of the object causes undefined behavior, as does dereferencing a pointer to one element past the end of the object obtained through the pointer arithmetic. So even if you had a struct containing three int
s with no padding inbetween and took a pointer to the first int
and incremented it to point to the second int, dereferencing it would cause undefined behavior.
More from 6.5.6: (bold-italic emphasis mine)
Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the
array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. 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.
A fourth issue is that dereferencing a pointer to one type as another type results in undefined behavior. This attempt at type-punning is often referred to as a strict-aliasing violation. The following is an example of undefined behavior through strict-aliasing violation even though the data types are the same size (assuming 4-byte int and float) and nicely aligned:
int x = 1;
float y = *(float *)&x;
6.5 p7:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
a type compatible with the effective type of the object,
a qualified version of a type compatible with the effective type
of the object,
a type that is the signed or unsigned type corresponding
to the effective type of the object,
a type that is the signed or unsigned type corresponding to a
qualified version of the effective type of the object,
an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively, a
member of a subaggregate or contained union), or
a character type.
Summary:
No, a C struct does not necessarily hold its members in contiguous memory, and even if it did, the pointer arithmetic you still couldn't do what you want to do with pointer arithemetic.