2009-04-27 1 views
5

Извините, если это нуб вопрос :(Слишком много элементов в массиве! ..?!

Кусок кода C

int array[5]; 
int cnt; 

for(cnt = 0; cnt <= 10; cnt+=1) 
{ 
     array[cnt] = cnt; 
} 

Если выдаст ошибку, право не работает нормально Но почему это кажется, что!? - в первой строке - массив из более чем двойного размера (11). Вы можете даже получить доступ к массиву [5-10] позже. И это меня смущает. Он перестает работать, когда вы определяете массив [4 или меньше] ...

Заранее благодарен

ответ

23

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

Поведение вашего кода в соответствии со спецификацией языка C: undefined. Это означает, что он может делать то, что вы надеетесь, или это может привести к сбою компьютера или может привести к ошибке demons to fly out your nose.

В отличие от языков более высокого уровня, таких как Java и C#, C доверяет вам и не выполняет явные проверки границ массивов. Вы должны быть ответственными, а не выступать за пределы массива.

+3

+1 для предотвращения носового демона! – RBerteig

+2

@RBerteig: Я не думаю, что «defenestration» (defenstration - это не слово) означает, что вы думаете, что это значит. По-английски это было бы тем, что кто-то бросал кого-то через окно. http://en.wikipedia.org/wiki/Defenestration –

+0

Опечатка, действительно, но выбор слова был преднамеренным. Я стремился к чему-то, что вселилось в «демона», которое имело правильное количество неожиданного изгнания. Это было растяжкой и, возможно, пробив точку метафоры ;-) – RBerteig

4

«Но почему это?»

Потому что это путь С.

Границы массива не проверяются во время выполнения.

Это «Закон C»

16

Это только «работает», если ваше определение «работ» является синонимом «еще не разбился».

+2

+1: мне, возможно, придется «заимствовать» эту строку для моего следующего обзора кода ;-) – RBerteig

+1

Есть ли еще определение "работы"? – spiderman

+0

Отличная цитата, спасибо! – Charlie

0

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

0

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

5

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

2

Массивы в C не проверяются во время выполнения. Другими словами, вы можете «определить» массив размера N и счастливо получить доступ к концу границы массива. Если вы уйдете с конца массива, вы будете удалять память где-нибудь в стеке (или в кучу).

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

Обычно при объявлении массивов в C, то лучше использовать какое-то постоянная или #define, чтобы отметить размер массива:

#define MAX_ELEMENTS 10 
int array[MAX_ELEMENTS]; 
int cnt; 
for(cnt = 0; cnt < MAX_ELEMENTS; cnt+=1) { 
    array[cnt] = cnt; 
} 

Если пройти MAX_ELEMENTS в назначении массива, вы могли бы перезаписать значение cnt.Вы можете перезаписать другую переменную. Все зависит от компилятора и структуры кода. Также обратите внимание на использование знака < в цикле for. C массивы основаны на 0, поэтому вам нужно проверить, используя меньше, а не меньше или равно.

4

Я просто хочу указать, что все это действительно не определено. Ваш пример «работает» в этом конкретном примере, потому что обе переменные находятся в стеке. То есть адрес cnt находится чуть ниже конца массива. Когда cnt достигает cnt == 5 массив операторов [cnt] = cnt; не записывает в память, выделенную для массива, а сразу после нее, где находится адрес cnt. Просто удача в том, что она не изменит ваш счетчик. Когда cnt> 5 нет памяти для мусора, и он просто напишет в «стеке пустоты» (не знаю правильного слова).

еще один пример для иллюстрации этого:

int main(int ac,char **av) 
{ 
    int a[5]; 
    int cnt; 
    int cnt2=3; 

    for(cnt=0;cnt<7;cnt++) { 
     a[cnt]=cnt; 
     printf("%d %d %d\n", a[cnt], cnt, cnt2); 
    } 
} 

выход:

0 0 3 
1 1 3 
2 2 3 
3 3 3 
4 4 3 
5 5 5 
6 6 5 

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

+0

Nice иллюстрации. К сожалению, я не могу отметить два лучших ответа здесь. : \ – spiderman

1

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