2011-01-28 4 views
2

это даст правильный выход, даже если я не выделенную памяти и объявил указатель на структуру два внутри основногоуказателя на структуру

struct one 
    { 
    char x; 
    int y; 
    }; 

    struct two 
    { 
    char a; 
    struct one * ONE; 
    }; 

    main() 
    { 
    struct two *TWO; 
    scanf("%d",&TWO->ONE->y); 
    printf("%d\n",TWO->ONE->y); 
    } 

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

struct one 
    { 
    char x; 
    int y; 
    }; 

    struct two 
    { 
    char a; 
    struct one * ONE; 
    }*TWO; 


    main() 
    { 
    scanf("%d",&TWO->ONE->y); 
    printf("%d\n",TWO->ONE->y); 
    } 
+0

Какова цель сравнения двух неправильных вещей? – DReJ

+0

Какой компилятор вы используете? Запуск вашей первой программы под gcc (cygwin) дает мне ошибку сегментации. – pankajt

+0

@ Devil Jin: gcc – Manu

ответ

1

Потому что вы делаете это неопределенное поведение. Иногда это работает. Это не значит, что вы должны это сделать :-)

Наиболее вероятное объяснение заключается в том, как инициализировать переменные. Автоматические переменные (в стеке) получат всякий мусор, находящийся в стеке, когда указатель стека был уменьшен.

Переменные внешних функций (как во втором случае) всегда инициализируются нулем (нулевой указатель на типы указателей).

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

+0

paxdiablo @ первый случай работает каждый раз, когда я запускаю программу ... – Manu

+0

@Manu, в отсутствие чего-либо изменяющегося, вероятно, он будет «работать». Обратите внимание на цитаты вокруг «работающих», поскольку это не делает правильной вещи вообще. _Any_ change (новый компилятор, новый компоновщик, измененная структура памяти в ОС, тот факт, что это четверг и т. Д.) Могут нарушить ваши планы. Итог, ISO заявили, что то, что вы делаете, нельзя доверять. Прекратите делать это. Теперь. Не заставляй меня приходить туда :-) – paxdiablo

3

В обоих случаях TWO является указателем объекту типа struct two.

В случае 1 указатель дикий и может указывать в любом месте.

В случае 2 указатель NULL, поскольку он является глобальным.

Но в обоих случаях это указатель, не указывающий на действуетstruct two объект. Ваш код в scanf обрабатывает этот указатель так, как если бы он ссылался на действительный объект. Это приводит к неопределенному поведению.

1

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

При объявлении автоматического указателя его начальное значение, вероятно, будет намного интереснее. В этом случае, независимо от того, какая библиотека времени выполнения осталась в этой точке стека перед вызовом main(), или, возможно, значение слева от созданного компилятором кода установки стекового кадра. Скорее всего, это будет сохраненный указатель стека или указатель кадра, который является допустимым указателем, если он используется с небольшими смещениями.

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

И это, потому что ошибка сегментации является механизмом ОС, а не языком С.

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

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