2015-01-14 6 views
3

Я программист и начинающий C++. Я был бы признателен за помощь в этом.Указатель ведет себя странно

следующая программа (в C++) не возникнут какие-либо проблемы, либо во время компиляции или во время выполнения:

int main() 
{ 
    int b = 5; 
    int*a = &b; 
    *(a+5) = 6; 
    return 0; 

} 

Но, по всему, что я узнал, он не должен работать, потому что это указатель единственная переменная. Что мне здесь не хватает?

+0

Что не должен работать обращается к +5 – CashCow

+0

Я думаю, что он/она путает арифметику указателей. –

+0

a просто указывает на ячейку памяти b. Почему вы думаете, что это не должно работать? (a + 5), скорее всего, будет топать в некоторой памяти, но в противном случае я не вижу проблемы. – PixelCloudSt

ответ

6

Ваша программа не должна сталкиваться с какой-либо проблемой во время компиляции. Это все допустимый код в отношении компиляции.

Однако он будет сталкиваться с неопределенным поведением во время выполнения, поскольку a+5 недействительный адрес.

Если вы хотите знать, почему он должен собрать, вы можете написать код так:

int func(int * buf, size_t size) 
{ 
    for(size_t i = 0; i < size; ++i) 
    { 
     *(buf + size) = static_cast<int>(i); // or (int)i in C 
    } 
} 

int main() 
{ 
    int buf[ 6 ]; 
    func(buf, 6); 
} 

В коде a является указателем на память. a + 5 означает адрес 5 "ints", откуда a баллов. Поскольку a было указано на одно целое число b, никаких гарантий относительно такого адреса нет. Интересно отметить, что он определенно относится к a+1, хотя он указывает на место в памяти, которое вы не должны читать или писать. Но сам указатель имеет некоторые гарантии, то есть он будет больше a, и если вы вычтете 1 из него, вы вернетесь к a, и если вы сделаете ptrdiff между ним и a, вы получите 1. Но это просто специальное свойство «один за другим», который позволяет программистам указывать диапазоны памяти.

+0

Мне нравится этот ответ :) Тем не менее, вероятно, целесообразно объяснить разницу между неопределенным поведением и «не должно работать» с этим аськой :) –

+0

Поведение не определено и зависит от архитектуры процессора, как он обрабатывает стек , 'a + 5' является действительным адресом, и с ним вообще не может быть никаких проблем. Память 'b' находится в стеке, поэтому' a + 5' на пять значений превышает адресное пространство, чем адрес 'b'. Если стек возрастает, проблем не будет, так как это будет неиспользуемая память. Если он спускается, может быть, большой упс. –

+1

a + 5 не является действительным адресом. a + 1, хотя вы не можете разыменовать его. – CashCow

0

Да, он не должен работать, когда вы получаете доступ к свободному пространству памяти, которое не находится в вашей области процесса, но, возможно, никто не владел этим конкретным регионом ((a + 5)), который не вызывал вредоносного доступа в режиме времени или он мог. Отсюда и UB.

1

Программа действительно есть неопределенное поведение:

int main() 
{ 
    //This cause the loading of the "main" function to allocate memory for variable b 
    //It could be in a memory page that was already allocated to the program 
    //or in a new allocated page. 
    int b = 5; 

    //Here a just getting the address of variable b. 
    int*a = &b; 

    //This is the undefined behavior and can end up in two cases: 
    // 1. If (a+5) value is in a memory space that is allocated to the application. 
    // Then no runtime error will happen, and the value will be writing there. 
    // probably dirting some other value, and can cause an undefined behavior later 
    // in the application execution. 
    // 2. If (a+5) value is in a memory space that wasn't allocated to the application. 
    // the application will crash 
    *(a+5) = 6; 
    return 0; 

} 

Теперь, так как размер страницы, вероятно, 4096 б где-то в пределах страницы, * б + 5 в большинстве случаев по-прежнему находиться в такой же страница. Если вы хотите бросить вызов, это больше изменит его с 5 до 5000 или выше, и вероятность сбоев увеличится.

0

Просто добавьте существующие ответы.

Доступ

*(a+5) = a[5] 

Так что это место не выделяется вами.

В случае массива говорит

int a[6]; 

У вас есть право на доступ от a[0] к a[5] где a[5] последний элемент массива и любого дальнейшего доступа как a[6] приведет к непредсказуемому поведению, как местоположение не выделенные вами.

Аналогично вы просто целое число выделяется как

int b=5; 

int *a = &b; 

а есть указатель, указывающий на &b т.е. адрес б.

Таким образом, действительный доступ для этого всего a[0], который является единственным местом, выделенным вами в стеке.

Любой другой доступ, такой как a[1] a[2]... и т. Д., Приведет к неопределенному поведению.

Доступ оказывается ДЕЙСТВИТЕЛЬНЫЙ если у вас есть что-то вроде

int b[6]; 
int *a = b; 

Теперь a[5] даст значение последнего элемента массива b

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