Почему этот кусок кода ведет себя странно? - PullRequest
0 голосов
/ 19 февраля 2012

У меня есть этот код на C ++, который дает странный вывод:

#include<iostream>
using namespace std;
int main(){
    int r[15]={0};
    int n = 5;
    r[15]=20;
    cout<<n;    
}

Вывод, очевидно, должен быть 5, но он дает мне 20. Теперь я знаю, что r [15] выходит за пределы.Этот код должен был вызвать исключение при попытке доступа к r [15], не так ли?Тем не менее, он обычно компилируется с g ++ и выдает неправильный вывод.Я не могу понять, что является причиной этой аномалии.Кто-нибудь может помочь?

Просто к вашему сведению, этот код является просто примером, я должен был выяснить эту ошибку из более крупного кода, который занял у меня много времени, который, в противном случае, мог бы быть сохранен, если исключениебыл брошен.

Обновление: Я проверил следующий код:

#include<iostream>
using namespace std;
int main(){
    int n = 5;
    int r[15]={0};
    r[15]=20;
    cout<<n;
}

Output:
20

Я также проверил следующий код:

#include<iostream>
using namespace std;
int main(){
    int n = 5;
    int a=5;
    int r[15]={0};
    r[15]=20;
    cout<<n<<endl<<a;
}

Output:
5
5

Итакобъяснение стека верное, в этом случае тоже должно быть изменено любое из значений, верно?Это не так.

Ответы [ 2 ]

9 голосов
/ 19 февраля 2012

Поскольку r является массивом из 15 элементов, r[14] является последним элементом. Поэтому r[15]=20; - неопределенное поведение. C ++ не выполняет проверку границ, поэтому вы не получите исключений при работе с простыми массивами.

В вашем случае r[15]=20 происходит перезапись стека в точном месте, где хранится n.

5 голосов
/ 19 февраля 2012

Теперь я знаю, r[15] выходит за пределы.Этот код должен был вызвать исключение при попытке доступа к r[15], не так ли?

Нет, если вы не используете какую-то библиотеку проверки, нет.C (и C ++) очень близки к машине , поэтому вы можете оказаться в такой ситуации.(Это часть их возможностей.) В некоторых компиляторах есть флаги компилятора, которые вставляют проверку границ (за счет времени выполнения), но gcc этого не делает (вы можете найти наборы патчей, чтобы добавить его в качестве функции, хотя ядумайте только о C).

То, что там произошло (очевидно), заключается в том, что ваша переменная n попадает в стек сразу после 15 слотов массива r:

+-------+
| r[0]  |
| r[1]  |
| r[2]  |
...
| r[13] |
| r[14] |
| n     |
+-------+

... и поэтому запись в вашу запись за пределами допустимого диапазона r[15] в конечном итоге перезаписывает ее (в вашем конкретном случае; это не поведение, на которое вы можете или должны рассчитывать, порядок вещей в стеке не определяется какопределяется порядком, в котором они объявлены в источнике, и вполне может не быть).

...