указатель на структуру - PullRequest
       0

указатель на структуру

2 голосов
/ 28 января 2011

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

    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);
    }

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

    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);
    }

Ответы [ 3 ]

3 голосов
/ 28 января 2011

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

В случае 1 указатель является диким и может указывать куда угодно.

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

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

2 голосов
/ 28 января 2011

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

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

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

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

1 голос
/ 28 января 2011

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...