Let's see for ourselves!
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
void printhex(const void *pnt0, size_t s)
{
    const unsigned char *pnt = pnt0;
    while(s--) {
        printf("%02x", *pnt++);
    }
}
void printhexln(const char *pre, const void *pnt, size_t s, const char *post)
{
    printf("%s", pre);
    printhex(pnt, s);
    printf("%s", post);
    printf("\n");
}
struct Struct_1 {
    unsigned int data1, data2;
};
struct Struct_2 {
    unsigned int data3, data4;
};
int main()
{
    // let's grab memory for 4 ints
    size_t size = 4 * sizeof(int);
    void * ptr = malloc(size);
    assert(ptr != NULL);
    // let's zero that memory
    memset(ptr, 0, size);
    // this will print zeros
    printhexln("1: ", ptr, size, "");
    ( (struct Struct_1 *)ptr ) -> data1 = 0x1122;
    printhexln("2: ", ptr, size, "");
    ( (struct Struct_1 *)ptr ) -> data2 = 0x3344;
    printhexln("3: ", ptr, size, "");
    ( (struct Struct_2 *)ptr ) -> data3 = 0x5566;
    printhexln("4: ", ptr, size, "");
    ( (struct Struct_2 *)ptr ) -> data4 = 0x7788;
    printhexln("5: ", ptr, size, "");
    free(ptr);
    return 0;
}
will output on https://www.onlinegdb.com :
1: 00000000000000000000000000000000
2: 22110000000000000000000000000000
3: 22110000443300000000000000000000
4: 66550000443300000000000000000000
5: 66550000887700000000000000000000
printhex is a simple function that prints the memory behind a pointer in hexadecimal characters. We can see that:
- first there are only zeros. We can count zeros and we see that size = 16andsizeof(int) = 4.
- We then cast the pointer to struct Struct_1 and set data1 to 0x1122. The first 2 bytes of the pointer are overwritten and set to 0x2211, because the machine is little endian. The value of ((struct Struct_1)ptr)->data1is now equal to0x00001122.
- We can see that writing 4433 to ((struct Struct_1*)pnt)->data2 sets byte 5 and 6 to 0x4433. Machine is little endian, sizeof(int) = 4and we can see thatoffsetof(struct Struct_1, data2) = 4
- Casting the struct to Struct_2 and writing to data3, overwrite first 2 bytes, not caring about the previous values. That's because offsetof(struct Struct_2, data3) = 0, so data3 starts at the beginning of the pointer.
- Well, 4433 is overwritten by 8877 when writing to the data4 member of Struct_2