views:

446

answers:

9

Sorry if this is a noob question :( .

Piece of C code.

int array[5];
int cnt;

for(cnt = 0; cnt <= 10; cnt+=1)
{
      array[cnt] = cnt;
}

Should give an error, right? No! Works fine! But why is that? It seems that -in the first line- an array of more than the double size (11) is defined. You can even access array[5 to 10] later on. And that is confusing me. It stops working when you define array[4 or less] ...

Thanks in advance.

+22  A: 

It may happen to work with your particular compiler and computer, but you shouldn't count on it.

The behaviour of your code according to the C language specification is undefined. This means that it might do what you hope, or it might cause your computer to crash, or it might cause demons to fly out your nose.

Unlike higher-level languages such as Java and C#, C trusts you and does not perform explicit checks on the bounds of arrays. You are supposed to be responsible and not tread outside the boundaries of the array.

Simon Nickerson
+1 for nasal demon defenstration!
RBerteig
@RBerteig: I don't think "defenestration" (defenstration isn't a word) means what you think it means. In English, that would be the act of throwing someone/something through a window. http://en.wikipedia.org/wiki/Defenestration
Evan Teran
A typo, indeed, but the word choice was deliberate. I was reaching for something that alliterated with "demon" that had the right amount of a sense of unexpected expulsion. It was a stretch, and possibly past the metaphor's breaking point ;-)
RBerteig
@Evan Teran - Inigo Montoya approves ;)
Richard Szalay
+4  A: 

"But why is that?"

Because that's the way C is.

Array bounds are not checked at run time.

That's the "Law of the C"

S.Lott
+15  A: 

This only "works" if your definition of "works" is synonymous with "hasn't crashed yet".

Don Neufeld
+1: I may have to "borrow" that line for my next code review ;-)
RBerteig
Is there another definition of "works" ?
spiderman
What a great quote, thanks!
Charlie
A: 

Once you run off the end of the array, you are overwriting memory that the software is not expecting and corrupting the heap. You software may continue to run, but it will be very unstable!

Colin Desmond
A: 

Depends on how the stack memory is packed. Also, it will happily overwrite those values and even read them, but most likely you are corrupting the stack.

+5  A: 

What you are seeing is undefined behaviour, caused by you accessing the array with an invalid index. Undefined behaviour means that anything could happen, including your program appearing to work correctly.

anon
+2  A: 

Arrays in C are not checked at runtime. In other words, you can "define" an array of size N and happily access off of the end of the array bound. If you go off the end of the array, then you will trash memory somewhere on the stack (or the heap).

Once you trash memory somewhere, your program is likely to crash. These crashes can be hard to track down because they might crash far away from where you actually overran the end of the array.

Typically when you declare arrays in C, it's best to use some sort of constant or #define to mark the size of the array:

#define MAX_ELEMENTS 10
int array[MAX_ELEMENTS];
int cnt;
for(cnt = 0; cnt < MAX_ELEMENTS; cnt+=1) {
   array[cnt] = cnt;
}

If you go past MAX_ELEMENTS in the array assignment, you might overwrite the value of cnt. You might overwrite some other variable. All depends on the compiler and the code structure. Also note the use of the < sign in the for loop. C arrays are 0 based so you have to check using less-than and not less-than-or-equal-to.

Mark
+4  A: 

I just like to point out that all this is indeed undefined. Your example "works" in this specific example because both variables are located on the stack. That is the address of cnt is just below the end of the array. When cnt reaches cnt==5 the statement array[cnt]=cnt; does not write in the memory dedicated to the array but just after it, where the address of cnt lay. It is just luck that it does not alter your counter. When cnt>5 there is no memory to trash and it will just write in the "stack void" (don't know the proper word).

another example to illustrate this:

int main(int ac,char **av)
{
    int a[5];
    int cnt;
    int cnt2=3;

    for(cnt=0;cnt<7;cnt++) {
        a[cnt]=cnt;
        printf("%d %d %d\n", a[cnt], cnt, cnt2);
    }
}

output:

0 0 3
1 1 3
2 2 3
3 3 3
4 4 3
5 5 5
6 6 5

The last two writes of the loop overwrites the stack data after a[] and may yield very confusing errors. In this case the cnt2 is trashed.

Nice illustration. Unfortunately, I can't mark two best answers here. :\
spiderman
+1  A: 

Array bounds in C are not necessarily checked at runtime. The standard leaves implementors free to do so if they choose, or not - that's part of what is undefined. On an implementation with fat pointers the sample might indeed cause some sort of error.

mlp