Пример указателя в учебнике сбивает меня с толку

#c #pointers

#c #указатели

Вопрос:

В настоящее время я просматриваю указатели в классе, и наш учебник немного сбивает меня с толку. Они начинают с того, что говорят, что следующий пример копирует значение в месте, на которое указывает money , в место, на которое указывает MyMoney:

 *myMoney = *money;
  

Затем следующий пример копирует значение в деньгах в MyMoney

 myMoney = money;
  

Этот второй пример вызывает утечку памяти, потому что исходное местоположение, на которое указал * MyMoney, больше недоступно. Это потому, что память, которая использовалась для хранения указателя, теперь является фактическим значением с плавающей точкой вместо адреса памяти?

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

 char alpha[20];
char *alphaPtr;
char *letterPtr;
vod Process(char []);
.
.
alphaPtr = alpha;
letterPtr = amp;alpha[0];
Process(alpha);
  

Поскольку в книге говорится, что

 myMoney = money;
  

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

 alphaPtr = alpha;
  

также вызывает ссылку на память? Разве они не должны были объявить это как

 char *alphaPtr = *alpha;
  

Комментарии:

1. Я просто хотел поблагодарить всех вас, ребята, за предоставленную вами помощь!

Ответ №1:

Что нужно помнить:

  • myMoney и money являются указателями, поэтому myMoney = money; копирует один указатель поверх другого. Теперь у вас есть два указателя, указывающих на одно и то же (на что money указывало), и ничего, указывающего на то, на что myMoney раньше указывало (это утечка памяти).
  • *myMoney и *money это значения, на которые указывают указатели (потому что * разыменовывает указатель, чтобы получить то, на что он указывает), поэтому *myMoney = *money; копирует то, что money указывает на то, на что myMoney указывает; сами указатели не изменились.
  • alpha это массив, который может быть преобразован в указатель на первый элемент в массиве.
  • Утечки с alphaPtr нет, потому что в первую очередь это ни на что не указывало.
  • Да, char *alphaPtr = *alpha; это был бы гораздо лучший способ написать это, потому что тогда alphaPtr не тратится время на неинициализацию. Некоторые компиляторы даже предупредят вас, когда вы объявите неинициализированные указатели, подобные примеру из учебника.
  • Использование (разыменование) неинициализированного указателя — это плохо, поскольку это приводит к страшному неопределенному поведению. Ваша программа может аварийно завершиться немедленно, или она может завершиться намного позже, или она может просто повредить ваши данные, ничего вам не сообщив, и вы обнаружите это только через месяцы, если вообще когда-либо.

Комментарии:

1. Извините, просто исправил часть «ссылка».

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

3. Указатели — один из самых сложных предметов в программировании. Это требует перехода от алгеброподобного мышления «переменная содержит значение», потому что, если это указатель, переменная теперь просто содержит адрес значения, которое не имеет математической параллели (для студентов) (по крайней мере, за пределами информатики). наука).

Ответ №2:

Этот второй пример вызывает утечку памяти, потому что исходное местоположение, на которое указал * MyMoney, больше недоступно. Это потому, что память, которая использовалась для хранения указателя, теперь является фактическим значением с плавающей точкой вместо адреса памяти?

Ячейка памяти, хранящаяся в MyMoney, теперь потеряна. Если бы он был выделен, не было бы способа восстановить его адрес, чтобы освободить его.

В вашем втором примере массивы особенные в том, что ссылка на них по имени ссылается на их адрес.

Ответ №3:

Проблема с назначением указателей

 myMoney = money;
  

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

Комментарии:

1. Итак, если у меня никогда не будет указателя, указывающего на что-либо во время объявления, я ничего не теряю, когда я на самом деле назначу ему что-то позже?

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

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

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

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

Ответ №4:

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

alphaPtr = alpha это не утечка. alpha это фактическая память, alphaPtr просто указывает на нее. Даже если alphaPtr ему назначено указывать на что-то другое, alpha он существует в стеке и будет автоматически восстановлен, когда выйдет за пределы области видимости.

char *alphaPtr = *alpha не будет компилироваться. Вы пытаетесь присвоить char a char* , что недопустимо.

Комментарии:

1. Хорошо, я думал, что * alpha присвоит свой адрес * alphaPtr.

2. То, что вы присваиваете указателю, не имеет ничего общего с тем, произошла ли у вас просто утечка памяти. Ключ в следующем: указывало ли прежнее значение указателя на память, которая не отслеживается в другом месте? Другими словами, новое значение указателя не вызывает утечки, это старое значение. Поскольку старое значение недопустимо в случае alphaPtr , утечки нет.