2012-02-19 3 views
0

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

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

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

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

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

#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 

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

+0

Особенно, если вы изучаете, рассмотрите возможность использования 'std :: vector ' и 'at()' - намного проще в использовании, а 'at()' будет генерировать исключения, если задан неверный индекс. –

ответ

9

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

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

+0

Проверьте мое обновление. –

+2

@dpacmittal Неопределенное поведение. Прочтите мой ответ еще раз * тщательно *. «** переписывается» **. Нет никакой гарантии, компилятор может и будет изменять порядок вещей. Скажите это со мной: * неопределенное поведение *. – cnicutar

+0

Ах, спасибо.Это имеет смысл :) –

5

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

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

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

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

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

+0

Я не уверен, что ваше объяснение правильно, потому что проблема остается, даже если я объявляю n до r. Кроме того, если я введу новую переменную 'a', проблема исчезнет. Я обновлю свой вопрос и включу новый код. –

+1

@dpacmittal: Дело здесь в том, что присвоение 'r [15]' приводит к странному поведению. Это за гранью, поэтому не делайте этого. :-) Точное странное поведение, которое вы получите, будет зависеть от компилятора (по крайней мере) и, вполне возможно, среды выполнения. См. Последнее предложение в ответе, в частности бит * «... в вашем конкретном случае; ** это не поведение, которое вы можете или должны рассчитывать на **» *. –

+0

Да, я понял. Благодаря :) –

Смежные вопросы