Nie jest to zachowanie nieokreślone , niezależnie od tego, co mówi ktoś, urzędnik lub w inny sposób , ponieważ jest zdefiniowane przez standard. p->s, z wyjątkiem sytuacji, gdy jest używany jako lwartość, jest obliczany na wskaźnik identyczny z (char *)p + offsetof(struct T, s). W szczególności jest to prawidłowy charwskaźnik wewnątrz obiektu malloc, i istnieje 100 (lub więcej, zależnie od kwestii wyrównania) kolejnych adresów bezpośrednio po nim, które są również prawidłowe jako charobiekty wewnątrz przydzielonego obiektu. Fakt, że wskaźnik został wyprowadzony przy użyciu ->zamiast jawnego dodawania przesunięcia do wskaźnika zwróconego przez malloc, rzutowany do char *, jest nieistotny.
Technicznie rzecz biorąc, p->s[0]jest to pojedynczy element chartablicy wewnątrz struktury, kilka następnych elementów (np. p->s[1]Through p->s[3]) prawdopodobnie wypełnia bajty wewnątrz struktury, które mogą zostać uszkodzone, jeśli wykonasz przypisanie do struktury jako całości, ale nie jeśli uzyskasz dostęp tylko do poszczególnych członków, a pozostałe elementy to dodatkowe miejsce w przydzielonym obiekcie, z którego możesz dowolnie korzystać, o ile spełniasz wymagania dotyczące wyrównania (i charnie masz żadnych wymagań dotyczących wyrównania).
Jeśli obawiasz się, że możliwość nakładania się na bajty wypełniające w strukturze może w jakiś sposób wywołać demony nosowe, możesz tego uniknąć, zastępując 1in [1]wartością, która zapewnia, że na końcu struktury nie ma wypełnienia. Prostym, ale marnotrawnym sposobem byłoby utworzenie struktury z identycznymi składowymi, z wyjątkiem braku tablicy na końcu, i użycie s[sizeof struct that_other_struct];jej jako tablicy. Następnie p->s[i]jest jasno zdefiniowany jako element tablicy w strukturze for i<sizeof struct that_other_structi jako obiekt char pod adresem następującym po końcu struktury for i>=sizeof struct that_other_struct.
Edycja: W rzeczywistości, w powyższej sztuczce, aby uzyskać odpowiedni rozmiar, może być również konieczne umieszczenie unii zawierającej każdy prosty typ przed tablicą, aby upewnić się, że sama tablica zaczyna się od maksymalnego wyrównania, a nie w środku wypełnienia innego elementu . Ponownie, nie uważam, aby to wszystko było konieczne, ale oferuję to dla najbardziej paranoicznych prawników językowych.
Edycja 2: Nakładanie się bajtów wypełniających zdecydowanie nie stanowi problemu, ze względu na inną część standardu. C wymaga, aby jeśli dwie struktury zgadzały się w początkowym podciągu ich elementów, dostęp do wspólnych elementów początkowych można uzyskać za pomocą wskaźnika do dowolnego typu. W konsekwencji, gdyby struct Tzadeklarowano strukturę identyczną z, ale z większą tablicą końcową, element s[0]musiałby pokrywać się z elementem s[0]in struct T, a obecność tych dodatkowych elementów nie mogłaby wpływać ani na nią nie wpływać dostęp do wspólnych elementów większej struktury używając wskaźnika do struct T.