Что происходит, когда 2 указателя указывают на одну и ту же область и один из них освобождается? - PullRequest
3 голосов
/ 30 марта 2019
char *oldPointer, *newPointer;

oldPointer = (char*)malloc(1000);
newPointer = (char*)realloc(oldPointer, 2000)

Можно ли использовать oldPointer сейчас?

Что происходит сейчас?

oldPointer = newPointer;

Что будет, если free(newPointer)?

Ответы [ 4 ]

2 голосов
/ 30 марта 2019

Что происходит, когда 2 указателя указывают на одну и ту же область и 1 из них освобожден?

oldPointer = (char*)malloc(1000);
newPointer = (char*)realloc(oldPointer, 2000)

oldPointer и newPointer могут не указывать на одну и ту же область,Это то, что делает realloc().Новый указатель может отличаться, если диспетчер памяти решит это сделать (например, если в старой области недостаточно места для заполнения нового необходимого пространства).Предположение, что они указывают на одну и ту же область, вызывает неопределенное поведение (UB - может или не может работать не так, как вы ожидаете, что приводит к трудной отладке).

1 из них освобожден

После

oldPointer = (char*)malloc(1000);
newPointer = (char*)realloc(oldPointer, 2000)

Вы не можете использовать oldPointer после этого realloc.Существует только newPointer.Если вы освободили oldPointer и адрес изменился, UB (вероятен сбой).Если вы освободили oldPointer и это был тот же адрес, что и newPointer, это, конечно, то же самое, что и newPointer.

В любом случае, правило простое: не используйте oldPointer послеэто будет перераспределено.Если только

oldPointer = malloc(1000);
oldPointer = realloc(oldPointer, 2000);
^^^

вы не используете тот же указатель.Но не рекомендуется, если произошел сбой realloc, у вас нет следов ранее выделенного адреса (если вы не сохранили его);это утечка.

И не приводите malloc / realloc.

1 голос
/ 30 марта 2019

Вы не можете безопасно использовать любой указатель перед проверкой того, что произошло после realloc ().

Возможность 1:

realloc не удалась, тогда newpointer будет NULL и не может бытьиспользуется, но oldPointer может.

Возможность 2:

realloc успешно и did not должны переместить старый mallocпамятьВ этом случае вы можете использовать оба указателя.(Они содержат одно и то же значение адреса)

Возможность 3:

realloc преуспел , но должен был выделить память в другом месте и освободить старый блок памяти.Теперь oldPointer будет по-прежнему указывать на старый адрес памяти, который больше не действителен.Это называется висящим указателем.

Однако newPointer является допустимым и может использоваться.

0 голосов
/ 30 марта 2019

По по стандарту :

Функция free вызывает освобождение пространства, на которое указывает ptr, что делает его доступным для дальнейшего выделения. Если ptr является нулевым указателем, никаких действий не происходит. В противном случае, если аргумент не совпадает с указателем, ранее возвращенным функцией calloc, malloc или realloc, или , если пространство было освобождено вызовом free или realloc, поведение не определено .

0 голосов
/ 30 марта 2019

Можно ли использовать oldPointer сейчас?

Когда вы говорите "использоваться", я предполагаю, что вы имеете в виду "может ли указатель быть разыменованным ".Другими словами - это нормально делать *oldPointer или oldPointer[200] или что-то подобное.

Ответ таков: зависит от значения newPointer.

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

Следовательно, правильный способ использования realloc - сохранить возвращаемое значение в другом указателе и затем проверить NULL.Например,

oldPointer = (char*)malloc(1000);                // BTW: dont use cast
newPointer = (char*)realloc(oldPointer, 2000);   // BTW: dont use cast
if (newPointer == NULL)
{
    // realloc failed....

    // the value of oldPointer is still valid

    // It is ok to dereference oldPointer, e.g. using oldPointer[10]

    // Here you will normally have some error handling
}
else
{
    // realloc success

    // the value of oldPointer shall be considered invalid.
    // the value of oldPointer may NOT be dereferenced anymore.
    // also notice that you may NOT call free(oldPointer).

    // Normally we save the value of newPointer into oldPointer
    // so that the value of oldPointer becomes valid and usable again
    oldPointer = newPointer;
}

Что произойдет, если free (newPointer)?

Если newPointer указывает на ту же память, что и oldPointer, больше не будет разрешеноразыменование любого из указателей.Пример:

oldPointer = newPointer;
free(newPointer);
oldPointer[9] = something;  // Illegal !!
newPointer[9] = something;  // Illegal !!
...