Take the 2-minute tour ×

Browsing through some old C code, and I came across this snippet. I am thoroughly confused as to what is happening behind the scenes.

I don't have a full understanding of struct pointer usage and operability, and I can't quite understand how the memory is being stored and accessed in the following code.

struct x{
int i1;
int i2;
char ch1[8];
char ch2[8];

struct y{
long long int f1;
char f2[18];

int main(void)
struct x * myX;
struct y * myY;
myX = malloc(sizeof(struct x));
myX->i1 = 4096;
myX->i2 = 4096;
strcpy(myX->ch1,"Stephen ");
myY = (struct y *) myX;
printf("myY->f1 = %d\n", myY->f1);
printf("myY->f2 = %s\n", myY->f2);

This outputs

 myY->f1 = 4096
 myY->f2 = Stephen Goddard

After the cast, i1 is stored into myY->f1 and both ch1 & ch2 is stored in myY->f2. My question is how?. What does the memory content look like after the cast?

I know it has to do with the size of the struct and where the pointer is pointing (obviously), but after looking at this code, it has definitely made me realize my lack of understanding pointers.

Thank you

share|improve this question
The first strcpy call invoke undefined behavior too, since it overwrite an array element that doesn't exist, namely ch1[8]. –  Lorenzo Donati Sep 8 '13 at 21:28
add comment

3 Answers

up vote 2 down vote accepted

I am assuming a 32-bit int here. The memory behind struct x has 24 bytes, and the layout is as follows:

Bit   0000 0000 00111111 11112222
      0123 4567 89012345 67890123
Field  i1   i2     ch1      ch2

Here is what happens after the first strcpy:

Field  i1   i2     ch1      ch2
                Stephen \0
                  Zero terminator

Here is what happens after the second strcpy:

Field  i1   i2     ch1      ch2
                Stephen  Goddard\0
                           Zero terminator

Note how the terminating zero from the first strcpy gets written over to complete the string.

Here is the layout of struct y:

Bit   00000000 001111111111222222
      01234567 890123456789012345
Field     f1            f2

When you cast a pointer of struct x to struct y, you do not copy anything. The layout of struct y is aligned with the layout of struct x like a cookie cutter, and then the content of combined x.ch1 and x.ch2 is taken through the f2 "window":

Y Field    f1            f2
X Field  i1 | i2     ch1 |    ch2
                 Stephen  Goddard\0

As far as printing 4096 goes, that's undefined behavior: you are passing f1, which is of type long long int, to printf in a position of an int parameter, so printf "reinterprets" the data as an int, chopping off the upper half (undefined behavior). The number that you get if you use an appropriate format specifier is 17592186048512.

share|improve this answer
Why is it that f1 only stores 4096 and not 40964096? –  ElliotM Sep 8 '13 at 21:41
@ElliotM Actually, it stores 17592186048512. However, your program tells printf that it's an int, so %d chops off the other four bytes. –  dasblinkenlight Sep 8 '13 at 21:44
add comment

The memory isn't affected by the cast. The cast just treats one object as though it was of another one of a different type. If you will, think of the code as having a union { struct x a; struct y b; }, and then writing to a but reading from b.

This is undefined behaviour, but it so happens to come out that the various objects overlay each other so you see the observed result.

The first strcpy(myX->ch1,"Stephen "); is also undefined behaviour, since the buffer is too small for the string.

share|improve this answer
I guess my real question is, after the cast, how does myY->f2 now contain myX->ch1 & ch2? –  ElliotM Sep 8 '13 at 21:30
@ElliotM: The f2 subobject of the y struct sits at the same memory location as the ch1 subobject of the x struct; the first null terminator is overwritten by the second strcpy (note that there's a buffer overrun). –  Kerrek SB Sep 8 '13 at 21:32
add comment

As for the memory, it still holds only the values from the struct x that was initially malloced plus the two pointers myX and myY, both pointing at struct x.

However, it just so happens that ch1 and f2 begin at the same relative memory index 8 (and i1 and f1 do too, obviously, index 0) and f2 also overlaps with ch2, so you get:

                      i1    i2    ch1               ch2
from x's perspective: [int] [int] [char] [char] ... [char] ...
from y's perspective: [long long] [char] [char] ... [char] ...
                      f1          f2
                      0     4     8      9          16

This works because a long long is as long as two ints, namely 8 bytes.

share|improve this answer
add comment

Your Answer


