2013-06-25 3 views
1

У меня возникли проблемы с пониманием того, как работают некоторые указатели. Я всегда думал, что когда вы создали переменную-указатель (p), вы не могли бы почтить и присваивать (* p = значение), если вы не malloc'd для него (p = malloc (x)), или установите ее в адрес другой переменной (р = & а)Указатели разыменования без указания их на переменную

Однако в этом коде, первое задание работает последовательно, в то время как последний вызывает Segfault:

typedef struct 
{ 
    int value; 
} test_struct; 

int main(void) 
{ 
    //This works 
    int* colin; 
    *colin = 5; 

    //This never works 
    test_struct* carter; 
    carter->value = 5; 
} 

Почему первая одна работа, когда Colin ISN» t указывая на любую свободную память? И почему 2-й никогда не работает?

Я пишу это на C, но люди с знанием C++ также могут ответить на это.

Редактировать: Ладно, я понял, что первый тоже не должен работать, но почему он. Это то, что мне нужно.

+4

«вы не могли бы откликнуться и назначить (...), если вы не malloc'd для этого не сделали, или установите его на адрес другой переменной (...)« Это абсолютно верно. Так что не делай этого. «Почему первый работает, когда colin не указывает на какую-либо свободную память?» Потому что тебе не повезло. «И почему 2-й никогда не работает?» Потому что тебе повезло. –

+9

Неопределенное поведение. – SBI

+1

Маргинальное замечание к вашему последнему предложению: вы, кажется, считаете, что C - подмножество C++. К сожалению, это не так. –

ответ

7
// This works 
int* colin; 
*colin = 5; 

Добро пожаловать в неопределенное поведение: факт, что он не сбой, не означает, что он работает. Доступ к неинициализированному указателю всегда неправильный, но иногда он не падает.

не мог почтительное и назначить, если вы либо malloc'd пространство для него или установить его на адрес другой переменной

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

2

Я всегда думал, что когда вы создали переменную-указатель (p), вы не могли бы почтить и назначить (* p = значение), если вы не malloc'd для него (p = malloc (x)) , или установите его на адрес другой переменной (* p = & a)

Для практических целей вы считали правильным. Лучше продолжайте думать.

Если вы делаете то, что в вашем примере, поведение программы не определено. Что означает что-нибудь может случиться, в том числе вводящий в заблуждение «работает». Но это не что иное, как рецепт катастрофы.

+2

Компилятор может свободно что-либо делать - даже заставить демонов летать из вашего носа. – greyfade

0

Не казаться «Я тоже!» ответьте, но другие ответы не отвечают на ваш основной вопрос:

Хорошо, я понял, что первый тоже не должен работать, но почему это так. Это то, что мне нужно.

В этом случае вы вызываете Undefined Behavior. Как в стандартах C, так и в C++ ясно, что когда переменная неинициализирована, ее содержимое не определено. И когда он говорит неопределенный, значит, неизвестно. Эти указатели могут содержать буквально все. Поскольку они неинициализированы, они содержат всю память, находящуюся в месте, которое компилятор выбрал для этих двух переменных.

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

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

1

Я всегда думал, что, когда вы создали переменную указатель (р), не могли бы почтительное и назначить (* р = значение), если вы либо malloc'd пространство для него (р = таНос (х)) или установить его на адрес другой переменной (* р = &)

есть вещи в C, которые запрещены, так что C компилятор выдаст ошибку и откажется компилировать программу, и есть другие вещи, для которых стандарт C не определяет какого-либо поведения, поэтому нет ограничений на то, что может сделать реализация. Причина этого заключается в том, чтобы дать реализациям широкую широту в том, как они реализованы, и позволить им производить ver y быстрый код. Это отличается от более современных языков, которые придают большую ценность защите программистов от их собственных ошибок. Как следствие, для программиста возникает большая нагрузка для написания действительного кода.

Ваш код является примером, где поведение не определено. Компилятор не генерирует проверки, чтобы узнать, действительно ли значение p имеет место при разыменовании и назначении его ... он может содержать нежелательные сообщения, а хранилище может находиться в произвольном месте в памяти или может указывать на недоступную память и хранилище (есть другие возможности, поскольку поведение не определено, но это те, которые будут возникать в обычных реалиях реального мира). То, что ваш код разбился в одном магазине, но не другой, - это просто случайность, артефакт тонких деталей реализации ... другой компилятор, другая версия компилятора, небольшое изменение в вашем источнике ... любой из этих вещи и другие могут изменить результаты, изменив значение, которое оказалось в p ... какое-то произвольное значение осталось в стеке, потому что p - это переменная стека (стандарт языка C не предусматривает или не упоминает стек, а обычный реалистичные реализации выделяют auto переменных в стеке.)

Суть в том, что ваша программа, как вы знаете, неправильно, даже если она «разрешена». Как сказал в комментариях Р. Мартиньо Фернандес, вы unlucky, что первый магазин «работал» ... в коммерческом продукте, имея что-то вроде этого «работа», было бы крайне неудачным, потому что он может потерпеть неудачу в любое время, включая худшие возможные обстоятельства. Язык C не помогает вам здесь ... вам нужно быть очень дисциплинированным.