It is not undefined behavior, regardless of what anyone, official or otherwise, says, because it is defined by the standard. p->s
, except when used as an lvalue, evaluates to a pointer identical to (char *)p + offsetof(struct T, s)
. In particular, this is a valid char
pointer inside the malloc'd object, and there are 100 (or more, dependign on alignment considerations) successive addresses immediately following it which are also valid as char
objects inside the allocated object. The fact that the pointer was derived by using ->
instead of explicitly adding the offset to the pointer returned by malloc
, cast to char *
, is irrelevant.
Technically, p->s[0]
is the single element of the char
array inside the struct, the next few elements (e.g. p->s[1]
through p->s[3]
) are likely padding bytes inside the struct, which could be corrupted if you perform assignment to the struct as a whole but not if you merely access individual members, and the rest of the elements are additional space in the allocated object which you are free to use however you like, as long as you obey alignment requirements (and char
has no alignment requirements).
If you are worried that the possibility of overlapping with padding bytes in the struct might somehow invoke nasal demons, you could avoid this by replacing the 1
in [1]
with a value which ensures that there is no padding at the end of the struct. A simple but wasteful way to do this would be to make a struct with identical members except no array at the end, and use s[sizeof struct that_other_struct];
for the array. Then, p->s[i]
is clearly defined as an element of the array in the struct for i<sizeof struct that_other_struct
and as a char object at an address following the end of the struct for i>=sizeof struct that_other_struct
.
Edit: Actually, in the above trick for getting the right size, you might also need to put a union containing every simple type before the array, to ensure that the array itself begins with maximal alignment rather than in the middle of some other element's padding. Again, I don't believe any of this is necessary, but I'm offering it up for the most paranoid of the language-lawyers out there.
Edit 2: The overlap with padding bytes is definitely not an issue, due to another part of the standard. C requires that if two structs agree in an initial subsequence of their elements, the common initial elements can be accessed via a pointer to either type. As a consequence, if a struct identical to struct T
but with a larger final array were declared, the element s[0]
would have to coincide with the element s[0]
in struct T
, and the presence of these additional elements could not affect or be affected by accessing common elements of the larger struct using a pointer to struct T
.