0

In this code below I try to access the '-1'th element of an array, I don't get any runtime error.

#include <stdio.h>

int A[10] = {0};

int main(){

    A[-1] += 12;

    printf("%d",A[-1]);

    return 0;
}

When I run the code, it outputs 12 that means it is adding 12 to the non-existent A[-1]. Till today whenever I had tried to access an out-of-bounds element, I had got a runtime-error. I had never tried it on a simple code before.

Can anyone explain why does my code run successfully?

I ran it on my computer and also on ideone, in both the cases it ran successfully.

2147483647
  • 1,177
  • 3
  • 13
  • 33
  • Undefined behaviour. You could if `A` was a pointer to not the first element, though, but that's more of a negative index thing than an out of bounds thing. – chris Feb 01 '13 at 05:32
  • I tried to access A[11] also, and it ran successfully. – 2147483647 Feb 01 '13 at 05:36
  • 3
    @A.06: Yes. "Undefined behavior" includes "it ran successfully". Undefined behavior also includes "horribly crashing" and "unicorns fly out from your computer screen". It *literally* means you can't reason about its behavior with any kind of reliability, which is why UB is exactly what you *don't* want to do. – In silico Feb 01 '13 at 05:37
  • 1
    [Undefined behavior](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). – Lundin Feb 01 '13 at 07:10

3 Answers3

1

C and C++ does not have any bounds checking. It is a part of the language. It is to enable the language to execute faster.

If you want bounds checking use another language that has it. Java perhaps?

As your code executes you are just lucky.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
1

In C++ (and C), the arrays don't check out of range indices. They're not classes.

In C++11, however you could use std::array<int,10> and at() function as:

std::array<int,10> arr;

arr.at(-1) = 100; //it throws std::out_of_range exception

Or you can use std::vector<int> and at() member function.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

You see, when you allocate a variable like this, it lands on the stack. Stack holds small packages of information about local variables in each function you call, to say it in simple words. The runtime is able to check, whether you exceed the bounds of allocated stack, but not if you write some data in the invalid place on the stack. The stack may look like the following:

[4 bytes - some ptr][4 bytes - A's first element][4 bytes - A's second element] ...

When you try to assign to -1th element of an array, you actually attempt to read four bytes preceding the array (four bytes, because it's an int array). You overwrite some data held on stack - but that's still in valid process's memory, so there are no complaints from the system.

Try running this code in release mode in Visual Studio:

#include <stdio.h>

int main(int argc, char * argv[])
{
    // NEVER DO IT ON PURPOSE!
    int i = 0;
    int A[5];

    A[-1] = 42;
    printf("%d\n", i);

    getchar();
    return 0;
}

Edit: in response to comments.

I missed the fact, that A is global. It won't be held in stack, but instead (mostly probably) in .data segment of the binary module, however the rest of explanation stands: A[-1] is still within process's memory, so assignment won't raise AV. However, such assignment will overwrite something, that is before A (possibly a pointer or other part of the binary module) resulting in undefined behavior.

Note, that my example may work and may not, depending on compiler (or compiler mode). For example, in debug mode the program returns 0 - I guess, that memory manager inserts some sentry data between stack frames to catch errors like buffer over/underrun.

Spook
  • 25,318
  • 18
  • 90
  • 167
  • 3
    Except the definiton `int A[10] = {0};` (in the OP's code) is outside the body of any function so i doubt `A` is created on the stack in that case :) – Maciej Hehl Feb 01 '13 at 05:44
  • Ah, you're correct. However I guess, that it's still a matter of writing inside process's memory, what makes this code not to crash. – Spook Feb 01 '13 at 05:47
  • @Spook, It's a reasonable explanation. Just don't count on that being the reason. It could just be the compiler being in a tricky mood :) – chris Feb 01 '13 at 05:53