Для цикла отсутствует несколько индексов с segfault - PullRequest
5 голосов
/ 01 июня 2009

Вывод приложения (внизу) выглядит следующим образом:

Индекс элемента: 0 Содержимое элемента: 22 * ​​1003 * Индекс элемента: 1 Содержимое элемента: 22 * ​​1004 * Индекс элемента: 2 Содержимое элемента: 22 * ​​1005 * Индекс элемента: 3 Содержимое элемента: 22 * ​​1006 * Индекс элемента: 4 Содержимое элемента: 22 * ​​1007 * Индекс элемента: 22 Содержимое элемента: 134513712

Почему элементы индекса, помеченные 5 - 21, пропущены? Я понимаю, что этот код может сделать segfault для границ переполнения массива, он предназначен для этого, меня не интересует, почему этот код плохой, просто почему пропускаются определенные индексы.

#include <stdio.h>
int main(){

int array[5];

int i;
for(i=0; i<10; ++i){
    array[i] = 22;
    printf("Element index number: %d Element contents: %d\n", i, array[i]);
}
return 0;
}

Ответы [ 5 ]

9 голосов
/ 01 июня 2009

Как только вы переполняете выделенную память, вы попадаете в «неопределенную территорию». Вероятно, запись в массив записывалась туда, где в стеке хранилось «i».

Обратите внимание, что в отличие от языков, таких как Java и C #, C не выполняет проверку границ во время выполнения, поэтому не гарантируется, что он сделает что-либо полезное (например, segfault) при переполнении массива, строки или неправильной памяти. Ничего не гарантировано. Он может рухнуть, он может продолжать бежать, , это может заставить демонов вылететь из носа .

7 голосов
/ 01 июня 2009

Что происходит, когда вы пишете в массив [5], вы пишете в i. Они находятся рядом в стеке, в памяти, поэтому вы можете ожидать такого поведения.

Думайте об этом так,

вы создали массив с 5 элементами в

int array[5];

на самом деле массив - это просто адрес. число в [] указывает, как далеко зашел этот адрес для доступа. Итак:

  • array [0] 0 ints в памяти после адреса "array"
  • массив [1] равен 1 дюйму в памяти после адреса "массив" ...
  • array [4] - это 4 дюйма в памяти после адреса «массив» (последний int, который вы зарезервировали для массива)

так что если вы доберетесь до

  • Массив [5] - это 5 дюймов в памяти после адреса "массив"

В C нет автоматической проверки границ, поэтому он рад перезаписать вашу собственную память. Вы поместили «i» после массива [5] в стеке, наиболее вероятно, что массив [5] - это i.

Вы просто устанавливаете массив [5], или i, равным 22, следовательно, я равен 22. Теперь, когда мне 22, ваш следующий поиск в массиве [i] действительно массив [22]. Это захватывает любой мусор, оказавшийся в этом месте в памяти; или, если вам повезет, вылетает.

2 голосов
/ 01 июня 2009

@ У Дуга есть, но давайте немного расширим.

У вас есть array [5] и i как авто переменные, поэтому они размещаются в стеке при входе, поэтому вы выделяете 6 ячеек: array [0], array [1], ... array [4], а потом я.

Когда вы устанавливаете i в 5, массив [i] указывает на ячейку в стеке, содержащую i. Вы тогда присвоили ему 22. Так что теперь я = 22, как вы напечатали.

Затем вы получаете массив [i] или массив [22], который находится внизу конца стека; случайное значение там оказывается таким большим числом.

0 голосов
/ 01 июня 2009

Вы объявили массив из 5 дюймов, но ваш цикл for записывает значения в 10 записей.

Изменить

int array[5];

до

int array[10];
0 голосов
/ 01 июня 2009

Скорее всего, хранилище для локальной переменной «i» находится сразу после «массива» в стеке, поэтому & array [5] == & i, что означает, что вы назначаете 22 для «i», когда вы назначаете 22 для массива [ 5].

...