Array size and addresses in C

When I compiled the following code, it shows that y and the beginning of the array are separated by 60 units. But according to my calculations, it should have been 4 * 10 (for array) + 4 (for k) + 4 (for y) = 48. Also, array [12] = 17 was assigned to element 12, since there is no element 12, the implementation had to go to y and overwrite y from 17. However, the console printed y = 10 instead ... im really confused ... Please Help!

 #include <stdio.h>

 int main(void) {
    int x = 42;
    int y = 10;
    int k = 10;
    int array[10];

    array[12] = 17;
    printf("array starts at %d\n", &array[0]);
    printf("x has the value %d\n", x);
    printf("x is stored in location %d\n", &x);

    printf("y has the value %d\n", y);
    printf("y is stored in location %d\n", &y);
 }

      

+2


source to share


12 replies


This is called undefined behavior (writing to array [12] in an array of 10 elements), so by definition you cannot know what it is supposed to do. There is no runtime check in C, so you can write wherever you want (well, for the sake of this example) and you cannot know what exactly will happen.



+7


source


When I compile this code (gcc on OSX) it tells me that y

yours is array

split into 8 bytes too . This is exactly what I was expecting ... the locals put it out like this:

int x = 42;
int y = 10;
int k = 10;
int array[10];

0                   1                   2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3...etc.
\__,__/ \__,__/ \__,__/ \__,__/ \__,__/ \__,__/
   x       y       k      [0]     [1]     [2]
                          array

      

The numbers are offsets from the bottom of the stack frame. So, x

fills in the bottom 4 bytes, 'y' stacks on top of it, and so on. The array is 40 bytes long, at the very top.



&y

is the start address y

, which is +4 bytes from the bottom of the stack. &array[0]

is the address of the beginning of the array, which is +12 bytes from the bottom of the stack frame.

By the way, you should probably format your addresses as "unsigned" -% u. Without this, large addresses may appear as negative numbers.

array[12]

goes beyond all of this, so you shouldn't expect it to affect y

. If you want to play with undefined then it array[-2]

might be equivalent y

. To get it to work like this I had to compile with optimizations - your mileage may change :)

+5


source


C does not guarantee that the variables you define at the top of the function are laid out in memory exactly one after the other, so you cannot guess anything about the location of the variable k

in relation to the location of the array in memory.

That this is 60 instead of 48 is probably because the compiler aligns the data in memory in some way (i.e., deliberately skips some bytes) to make it more efficient for the CPU to access the data (the CPU can get data from memory is faster if it is 8 or 16 bytes, for example how this works depends on the details of your processor). But really, k

and the array could also be divided into millions of bytes.

Note that your array contains 10 values. Trying to access elements outside of the 0 to 9 range is wrong as you are doing ( array[12]

). C does not check array bounds, but if you access an array with an invalid index, strange things can happen - your program could crash or have unexpected results.

+3


source


& x is the address of the variable "x" and has nothing to do with your array, except that it is stacked nearby.

To get the address of the element "xth" in an array, you need to use & array [x]

array [12] is off at the end of the array, so you are overwriting another variable on your stack. This could mean that another variable (like y) is being overwritten, or it could cause your program to crash catastrophically depending on what is stored in that location. You must access array of members [0] to array [9] in a 10-element array.

+2


source


C does not guarantee that the program will be the way you wrote it. This only guarantees what you have written. The compiler can move and optimize the variables in your code as long as it doesn't change the functionality of your code.

  • It is possible that some of the variables in your code are stored in permanent memory and not even on the stack.

  • C does not guarantee that the stack uses memory in reverse order.

+2


source


There is no guarantee that your variables are allocated in memory in any particular relationship with each other. Trying to modify array [12] is undefined behavior. It might change y, it might crash your program, it might do something else.

With that said, you can look at the addresses to try and figure out how your particular compiler laid out the variables in your particular program, at that particular time when it was compiled. To try this on my computer, I had to change the address print as my pointers are 64 bits and your program was trying to print them using ints, which are 32 bits. But after that changed, it turns out that y was placed 56 bytes after the start of the array, not 60 as your compiler did.

Then I compiled with optimizations and now y was 40 bytes after the start of the array (just after the end of the array) and x 44 bytes after (that is, just after y). array [12] also after that (remember, the last element in the array is numbered 9!), but by changing your array [12] to array [11], I got the program to print x as 17.

But, again, remember that all this behavior is undefined, and you shouldn't write programs that depend on variables placed by the compiler in any particular order.

+2


source


There is no guarantee that local variables are on the stack; the compiler could accept some variables in registers. Assuming alignment and case issues are resolved, x will always be in array [12], since array [9] is the last valid location in array [].

Doing this sort of thing is unsportsmanlike at best and always a bad idea.

+1


source


Two things

  • The reason [12] works is because this array was last stacked. In other words, there is nothing "above" so you can save by writing it. Try to switch the array with let say 'x' and you will most likely get a core dump

  • You are printing the memory address as "signed ints", so they probably come out as negative numbers. I would change '% d' to% u to see a positive number. You will see that the difference between them is 40, not 60. Not sure how you get 60, maybe you subtract them incorrectly.

+1


source


This is a DMA issue and why so many languages โ€‹โ€‹don't allow it now.

You can allocate an array of size 10, write 100 to an array location and it will work, but now you are overwriting memory that can be used by another program or your program, and therefore you might actually be corrupted by the application.

The only memory you can safely use is what you have allocated for your program. You have no idea where the x and y ints will be in your application, as they could be anywhere in memory, just as there are 4 bytes for your variable.

0


source


The question has already been answered, but I would like to point out that if you need this behavior, you can use it instead struct

.

struct {
    int array[10];
    int k;
    int x;
    int y;
} s;

s.k = s.y = 10;
s.x = 42;
s.array[12] = 17;
printf("array starts at %d\n", s.array);
printf("x has the value %d\n", s.x);
printf("x is stored in location %d\n", &s.x);

printf("y has the value %d\n", s.y);
printf("y is stored in location %d\n", &s.y);

      

0


source


As other people have pointed out, this behavior is undefined by the standard and can do almost anything. Also, if I change the printf format for the addresses to the more appropriate "% p", the output I get on Mac OS X looks like this:

array starts at 0xbffff7d4
x has the value 42
x is stored in location 0xbffff7cc
y has the value 10
y is stored in location 0xbffff7d0

      

So, in my case, the array is stored at a higher address than x or y. To see the entry at the end of the array, the declarations seem to have to be switched so that the x and y variables are allocated before the array.

When I do this, I get this:

array starts at 0xbffff7cc
x has the value 42
x is stored in location 0xbffff7f4
y has the value 10
y is stored in location 0xbffff7f8

      

So now they are in the correct order at least. However, there is no extra padding between the variables, so I need to set up the rewriting to array [10] to get this:

array starts at 0xbffff7cc
x has the value 17
x is stored in location 0xbffff7f4
y has the value 10
y is stored in location 0xbffff7f8

      

Success, sort of - I was able to rewrite the value of "x" through access to "array". As it turns out, changing almost all compiler parameters will change the addresses of various variables. This is what makes writing security related scripts as complex as possible ...

0


source


int array[10];

    array[12] = 17;

      

very funny...

Is that a question?

0


source







All Articles