2017-01-12 2 views
1
int main() 
{ 
    int i; 
    int vals[5]; 

    for (i = 0; i <= 5; i++) 
    { 
     vals[i] = 0; 
    } 
    printf("%d\n", i); 
    return 0; 
} 

Я пытаюсь изучить C из учебника университета. Они упоминали, что в приведенном выше коде:Бесконечная петля возникает при индексировании массива

Цикл обработки сбрасывается, когда я достигает 5, и программа проходит цикл снова и снова, повторно.

Я не мог понять, почему, и я попытался понять это на pythontutor.com, он дает 6 (теперь это экспериментально для C.). Каков правильный вывод и почему это происходит?

+2

Ваш код вызывает [UB] (http://en.cppreference.com/w/cpp/language/ub), 'vals [i]' будет пытаться получить доступ к vals [5] ', который выходит за рамки , – George

+0

Я пробовал ваш код на [Идеал] (http://ideone.com/aAzej4). Он выдавал результат как '6'. –

+1

Это _could_ приводит к бесконечному циклу из-за UB, но это может и не быть. Один из способов может привести к бесконечному циклу, если (a) 'i' хранится сразу после' vals', (b) 0 записывается в место хранения 'i' последней итерацией и (c)' i 'считывается из этого места хранения компилятором при выполнении теста' i <= 5'. –

ответ

6

Показатели массива в C основаны на 0. Поэтому, если ваш массив имеет размер 5, индексы идут от 0 до 4.

Вы петля for (i = 0; i <= 5; i++) достигает индекса 5, который находится за пределами массива.

Достижение вне границ буфера - неопределенное поведение в C. Любое разрешено. И ваша программа полностью сбивается, это один из возможных результатов.

Это возможно происходит потому, что массив и индекс находятся рядом друг с другом в памяти. Так vals[5] = 0 устанавливает i к нулю. И отныне условие цикла навсегда удовлетворено.

+1

Это можно определить чем-то вроде 'if (& i == & vals [5]) printf (« Тот же адрес \ n »);'. –

5

Этот код вызывает неопределенное bahavior. Что, конечно, означает, что то, что они заявили, могло на самом деле произошло. Но это во многом зависит от многих деталей.

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

vals[i] = 0; 

с i==5 вы могли фактически написать в месте, где i хранится. Но, с другой стороны, i можно просто удерживать в регистре или где-то еще в стеке, и вы не получите бесконечный цикл.

+0

Вместо «я мог бы просто держаться в целочисленном размере», «я» мог бы быть сохранен в другом месте », я думаю, будет яснее. –

+0

Спасибо. Я хотел написать реестр. Исправлено: – Gerhardh

+0

Возможно, лучшее слово, чем сброс, будет повреждено. –

0

Переменные, имеющие automatic storage class (переменные, созданные в функции, кроме static variables), создаются в стеке в C языках программирования.

Переменные в вашей программе также создаются в стеке. Поэтому переменные i, vals[0], vals[1], vals[2], vals[3] и vals[4] можно найти в стеке.

Помните: Индексы массивов в C programming language начинаются с 0. Если размер массива равен n, то индексы идут от 0 до (n-1).

Петля for в вашей программе пытается получить доступ к vals [5], когда ваша индексная переменная достигает 5. Достижение вне границ массива - это НЕОПРЕДЕЛЕННОЕ ПОВЕДЕНИЕ в C. Результат, который вы видели, является одним из возможных результатов. Так как в вашем стеке не существует vals[5], вы можете получить доступ к ячейке памяти, назначенной некоторой другой переменной, которая может быть ячейкой памяти, назначенной переменной i.Вы даже можете получить Ошибка сегментации, если вы получаете доступ к массиву из его привязки (Как я уже упоминал выше, результат не определен. Программа может работать без какой-либо ошибки сегментации или вы можете получить ее).

Рассмотрим картину, которую я создал:

enter image description here

В вашем случае массив (Vals) и индекс (я) может быть рядом друг с другом в стеке. Таким образом, vals[5] = 0 сбрасывает i до нуля и, следовательно, бесконечный цикл.

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