Почему следующий код не дает ошибки сегментации? - PullRequest
4 голосов
/ 10 сентября 2011

В следующей программе не должен ли код во 2-м цикле выдавать ошибку сегментации?
Может кто-нибудь объяснить, почему следующий код не выдает ошибку сегментации и работает должным образом?

Вывод: 2019 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1

#include <stdio.h>
#define N 20

int main(){
    int a[N];
    int i;

    for(i=0;i<N;i++){
        a[i]=20-i;
        printf("%3d ",a[i]);
    }

    printf("\n\n");

    for(i=0;i<N;i++){
        a[i]=a[a[i]];
        printf("%3d ",a[i]);
    }

    printf("\n\n");

    return 0;
}

Ответы [ 3 ]

10 голосов
/ 10 сентября 2011

Ваш массив находится в стеке.Запуск после конца обычно означает, что вы обращаетесь к мусору (и, следовательно, вызываете неопределенное поведение), но это не обязательно вызовет ошибку сегмента.

В вашем случае первый a[i]=20-i устанавливает первый элементк значению 20. Таким образом, первый a[i]=a[a[i]] инициирует доступ к a[20], который находится в конце.Но есть большая вероятность, что он на самом деле обращается к переменной i - при условии, что компилятор размещает ее сразу после массива - и i в настоящее время равен нулю, поэтому эффект nett будет a[0] = 0.Каждый последующий вызов a[i]=a[a[i]] гарантированно будет полностью в пределах, так как a[i] < 20.

2 голосов
/ 17 октября 2015

Комментарий Марсело кажется интуитивным, но на самом деле это не то, что происходит.Стек растет от High до Low.поэтому [19] будет по более высокому адресу, а [0] будет по более низкому адресу.Поскольку я определен после массива, он будет еще ниже в стеке.Так что [20] не указывает на i.Как уже упоминали другие, это просто мусорная стоимость.[-1] или [-2] (некоторые компиляторы допускают индексирование со знаком минус, что означает, что он опускается ниже) фактически указывают на i.(-2, потому что некоторые компиляторы могут поместить защитный байт (или 4 байта) после выделения массива, чтобы избежать атак переполнения буфера).

1 голос
/ 10 сентября 2011

Уверен, что все зависит от ОС в отношении ошибки, а не от компилятора. Ваш пробег может варьироваться в зависимости от системы и от того, сколько памяти выделено для стека. И я предполагаю, что пока вы находитесь в заранее выделенном стековом пространстве, оно не будет зависать. Это то, что особенно неприятно - он может работать очень хорошо и не говорить вам, что есть проблема, кроме того, что если вам повезет, это приводит к ошибочным результатам.

Если бы вы попытались получить, скажем, a[10000] - что-то, что ОС знает, не находится в пространстве ваших программ - что-то за пределами пространства, выделенного для стека, это вызвало бы ошибку.

...