Вы индексируете после конца массива ( переполнение буфера ) и переназначаете другие переменные в стеке.
int abc[3], i, j;
// Your stack looks like this (single 'x' is one byte):
// |abc[0]|abc[1]| abc[2]| j | i |
//
// |xxxx |xxxx |xxxx |xxxx|xxxx|
//
for(j=0; j<3; j++);
printf("%d\n", j);
// j = 3 at this point
// abc[3] points past the end of the array abc, in this case, at j.
// So the next statement increments j by 3.
abc[j] = abc[j] + 3;
printf("%d \n", j);
Чтобы проверить, попробуйте добавить следующие операторы вend:
printf("%d\n", &i == &abc[3]);
printf("%d\n", &j == &abc[3]);
EDIT
Точная структура стека будет зависеть от используемого вами компилятора:
misha@misha-desktop:~/Desktop/stackoverflow$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
misha@misha-desktop:~/Desktop/stackoverflow$ ./a.out
3
3
Вот почему он отлично работает на моей машине - оператор:
printf("abc: %x abc[3]: %x i: %x j: %x\n", &abc, &abc[3], &i, &j);
дает следующий вывод:
abc: 4cd0aa70 abc[3]: 4cd0aa7c i: 4cd0aa8c j: 4cd0aa88
Таким образом, стек на самом деле:
// aa70 aa74 aa78 aa7c aa88 aa8c
// |abc[0]|abc[1]| abc[2]| | .... | j | i |
Таким образом, когда он получает доступ к abc[3]
, он получает доступ к 0x4cd0aa7c
, который является просто "мертвым пространством".