Ожидаемая ошибка сегментации, как только значение будет присвоено индексу 1? - PullRequest
2 голосов
/ 19 июня 2010

В фрагменте кода я ожидал ошибку сегментации, как только попытался присвоить значение count[1]. Однако код продолжается и выполняет второй цикл for, указывая только на ошибку сегментации, когда программа завершается.

#include <stdio.h>

int main()
{
        int count[1];
        int i;

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

Может ли кто-нибудь объяснить, что происходит?

Причины редактирования: Улучшен пример кода согласно комментариям пользователей, int count[0] -> int count[1], Также избегайте пламенных войн.

Ответы [ 3 ]

15 голосов
/ 19 июня 2010

Вы пишете за пределами массива. Это не значит, что вы получите ошибку сегментации. Это просто означает, что у вас неопределенное поведение . Поведение вашей программы больше не ограничено стандартом Си. Может произойти все что угодно (в том числе программа, которая работает) - segfault - только один из возможных результатов.

На практике ошибка сегментации возникает, когда вы пытаетесь получить доступ к странице памяти, которая не отображается в вашем процессе операционной системой. Каждая страница имеет размер 4 КБ на типичном ПК с архитектурой x86, поэтому в основном вашему процессу предоставляется доступ к памяти частями по 4 КБ, и вы можете получить ошибку по умолчанию только в том случае, если вы пишете вне текущего блока.

С небольшими индексами, которые вы используете, вы все еще находитесь в пределах текущей страницы памяти, которая выделена вашему процессу, и поэтому ЦП не обнаруживает, что вы обращаетесь к памяти за пределами.

3 голосов
/ 19 июня 2010

Когда вы записываете за пределы массива, вы, вероятно, все еще записываете данные в область памяти, контролируемую вашим процессом; Вы также почти наверняка перезаписываете память, используемую другим программным обеспечением, таким как код управления кучей или стека. Только когда этот код выполняется, например, когда текущая функция пытается вернуться, ваш код может ошибиться. На самом деле, вы действительно надеетесь на ошибку сегмента.

2 голосов
/ 19 июня 2010

Ваш код не работает:

seg.c:5: warning: ISO C forbids zero-size array ‘count’

Всегда компилируйте с высокими уровнями предупреждения, например -Wall -pedantic для GCC.

Редактируйте:

То, что вы эффективноэто повреждение main функция s кадр стека .Поскольку в настоящее время стек в значительной степени всегда уменьшается, происходит следующее:

  • Первый цикл переопределяет стековую память, содержащую параметры main и адрес возврата в подпрограммах crt0.
  • Второй цикл успешно считывает эту память.
  • Когда main возвращает ошибку сегментации, запускается, так как адрес возврата fubar-ed.

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

Запустите программу из-под отладчика и проверьте адреса локальных переменных.В GDB вы можете сказать set backtrace past-main, поэтому backtrace покажет вам все процедуры, ведущие к main.

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

...