Что произойдет, если я дважды использую malloc на одном и том же указателе (C)?
Скажем, например, я создал указатель newPtr, и я использую malloc (некоторый размер), а затем я снова использую malloc (некоторый размер) с тем же указателем. Что происходит? Итак, я создаю второй блок памяти того же размера, что и первый? Указывает ли newPtr на тот же адрес?
Пример:
int *newPtr;
newPtr = malloc(10 * sizeof(int));
newPtr = malloc(10 * sizeof(int));
Ответы
Ответ 1
У вашей программы будет утечка памяти. Первое значение newPtr
будет потеряно, и вы не сможете free
его.
Затем я создаю второй блок памяти того же размера, что и первый?
Да. Вы выделяете второй объект, отличный от первого.
Указывает ли newPtr на тот же адрес?
Нет. Объекты различны, поэтому их адрес отличается.
Ответ 2
Фактически вы не используете malloc
на том же указателе. Вы не указываете указатель на malloc
вообще. malloc
всегда выделяет новую память. Итак, происходит то же самое, что и в случае с любым присваиванием переменной:
int a;
a = 14;
a = 20;
Что происходит с 14
? Вы не можете получить к нему доступ больше. В терминах malloc
это означает, что у вас больше нет ссылки на возвращаемый указатель, поэтому у вас будет утечка памяти.
Если вы действительно хотите использовать "malloc
с тем же указателем", вас может заинтересовать функция realloc
:
int *newPtr;
newPtr = malloc(10 * sizeof(int));
newPtr = realloc(newPtr, 10 * sizeof(int)); //*might leak memory*
Из этой ссылки: realloc
"изменяет размер блока памяти, на который указывает ptr. Функция может переместить блок памяти в новое место (адрес которого возвращается функцией).
EDIT: Обратите внимание, что если realloc
не работает в приведенном выше примере, он возвращает NULL, но память, на которую указывает newPtr
, не освобождается. Основываясь на этом ответе, вы можете сделать это:
void *emalloc(size_t amt){
void *v = malloc(amt);
if(!v) {
fprintf(stderr, "out of mem\n");
exit(EXIT_FAILURE);
}
return v;
}
void *erealloc(void *oldPtr, size_t amt){
void *v = realloc(oldPtr, amt);
if(!v) {
fprintf(stderr, "out of mem\n");
exit(EXIT_FAILURE);
}
return v;
}
а затем:
int *newPtr;
newPtr = emalloc(10 * sizeof(int));
newPtr = erealloc(newPtr, 10 * sizeof(int));
Ответ 3
Эти инструкции не используют malloc на newPtr
.
Заявление newPtr = malloc(10 * sizeof(int));
вызывает следующие операции:
-
sizeof(int)
.
- Это значение умножается на 10.
-
malloc
вызывается и этот продукт передается ему.
-
malloc
возвращает значение.
- Это значение присваивается
newPtr
.
Итак, вы видите, что на шаге 3 newPtr
никак не участвует. Только после malloc
выполняется newPtr
.
Когда вы вызываете malloc
второй раз, у него нет способа узнать, что вы делаете что-либо с newPtr
. Он просто выделяет новое пространство и возвращает указатель на него. Затем этому новому указателю присваивается newPtr
, который удаляет старое значение, которое было в newPtr
.
В этот момент у вас нет способа узнать, что такое старое значение. Пространство по-прежнему выделено, потому что оно не было освобождено, но у вас нет указателя на него.
Ответ 4
Вы не используете malloc на том же указателе. Вы вызываете malloc()
(который выделяет пространство и возвращает указатель на это пространство) и присваивая его возвращаемое значение одному и тому же объекту указателя. (malloc
сам не знает, что вы собираетесь делать с результатом, который он возвращает.)
Второе назначение, как и при любом назначении, заменит ранее сохраненное значение.
Это означает, что, если вы не сохранили его в другом месте, у вас больше нет указателя на первый выделенный фрагмент памяти. Это утечка памяти.
Кроме того, вы всегда должны проверять, является ли результат, возвращаемый malloc
нулевым указателем, и если да, предпримите некоторые корректирующие действия. В простейшем случае это может быть просто печать сообщения об ошибке и завершение программы. Вы определенно не должны предполагать, что вызов malloc
преуспел, а затем попытайтесь использовать (несуществующую) выделенную память. (Это не относится к вашему вопросу, но это то, что легко пропустило, тем более, что в большинстве контекстов неудачи распределения встречаются редко.)