2012-01-23 2 views
3

Пожалуйста, скажите мне разницу между стеком и кучей относительно ниже кодаразница между стека и кучи

int main() 
{ 
    int arr[3]; 
    int *a; 

    arr [5] = 6; // out of bound but it will not give error. 
    arr [3000] = 8 ; //SIGSEGV 

    a = malloc (sizeof (int)); 
    a[4] = 6; 
    a[4000] = 8; //No error 
} 

Я знаю, что аранжировка статический массив, и я доступ адрес какого-то другого процесса, когда я обр [ 3000], что дает ошибку SIGSEGV. Но я не понимаю, почему [4000] не даст мне никакой ошибки во время выполнения, т. Е. Сигнала SIGSEGV.

Благодаря

ответ

9

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

Обычно это называется undefined поведение. Нет никаких обещаний о том, что происходит, когда вы выписываете границы массива, все может или не может произойти.

+2

И, что еще хуже, неожиданные эффекты могут означать необнаруженное повреждение данных. – ninjalj

+0

@sth, спасибо за разъяснение моих сомнений. И спасибо всем, кто ответил. – sach

1

вороха является память, из которой таНос() блок памяти с.

a [4000] = 8; не сработало, потому что было удачей, что он не попал в адрес памяти другого процесса. Это было просто случайно

3

Ссылка на элементы вне границ массива - это неопределенное поведение, что означает, что все может произойти (исключение, исключение или другое). Причина, по которой присвоение arr[5] не вызвало ошибку, вероятно, связано с тем, что значение все еще находилось в допустимом пространстве стека (но это может привести к ошибкам позже в более продолжительном приложении). Недействительное присвоение выделенному массиву могло привести к записи на страницу в памяти, принадлежащей процессу, и, следовательно, не приведет к ошибке. Но это может измениться с момента запуска до запуска. И даже если адрес принадлежал странице вне адресного пространства процесса, это зависит от ОС от того, что на самом деле произойдет.

+1

, где дольше, вероятно, определено только как возвращение из этой функции – ninjalj

+0

@mark, поэтому, когда недопустимое присвоение выделенного массива может также вызвать ошибку сегментации? – sach

+0

@NikhilTej: Да, это конечно возможно. –

1

Все случаи, которые вы выделили, представляют собой «неопределенное поведение».

И в некоторых случаях это noop, а в других это ошибка сегментации.

Что особенно плохо относится к «неопределенному поведению», так это то, что он может работать как ожидалось в течение некоторого времени, но затем внезапно начинает создавать «нежелательные побочные эффекты» (например, ошибки сегментации). Это затрудняет отладку и воспроизведение этих условий в производстве.

1
int main() 
{ 
    int arr[3]; 
    int *a; 

    arr [5] = 6; // out of bound but it will not give error. 
// J: False - it is undefined. expect raptors, or something. 

    arr [3000] = 8 ; //SEGSEV 
// J: Now you see the effects of undefined behavior, even though you did not in a previous invalid access. 

    a = malloc (sizeof (int)); 
    a[4] = 6; // J: Still undefined behavior 
    a[4000] = 8; //No error 
// J: Still undefined behavior 
} 

Но я не понимаю, почему [4000] не будет давать мне ошибку времени выполнения т.е. ,. segsev сигнал.

Это будет на другой платформе или в архитектуре. Это действительно не имеет значения - вы всегда должны избегать UB.

Во всяком случае разница заключается в реализации распределителя вашей системы (при условии, что компилятор не поместил результат malloc в стек).

Как ваш распределитель управляет и распределяет память - это детали реализации, на которые нельзя положиться, особенно когда вы бросаете UB.

Распределитель может продавать куски памяти из большего физического распределения.Эта базовая реализация зависит от платформы.

1

Переполнение буфера - неопределенное поведение. Переполнение буфера может привести к сбою в понедельник, если оно находится в стеке и сбой на Tuedsay, если он находится в куче. Это просто неопределенное поведение.

Вот C параграф, который говорит, что это неопределенное поведение:

(C99, 6.5.6p8) «Если точки результат один за последним элементом массива объектов, он не должен использоваться как операнд унарного * оператора, который оценивается ».

И, конечно, [] замаскированная унарный оператор *:

(6.5.2.1p2) «Определение оператора индекса [] является то, что E1 [E2] совпадает с (* ((E1) + (E2))) «.

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