#c #malloc
#c #malloc
Вопрос:
Я смотрел урок на malloc
, и пока они выполняли конкретный пример, не имело смысла объяснять, зачем такому коду распечатывать весь указатель целиком.
#include <stdio.h&&t;
#include <stdlib.h&&t;
int main(void) {
int *list = malloc(3 * sizeof(int));
if (list == NULL)
return 1;
list[0] = 1;
list[1] = 2;
list[2] = 3;
int *tmp = malloc(4 * sizeof(int));
if (tmp == NULL)
return 1;
for (int i = 0; i < 3; i )
tmp[i] = list[i];
tmp[3] = 4;
free(list);
//From this line and below is the thin& in question.
list = tmp;
for (int i = 0; i < 4; i )
printf("%in", list[i]);
}
ВЫВОД:
~/test/ $ ./malloc_test
1
2
3
4
Насколько я понимаю free()
, это освобождает память, выделенную функциями распределения, и free()
«освободит» память указателя.
Если бы я руководствовался этим определением:
*list
было выделено 12 байт(3 * sizeof(int)
,sizeof(int) = 4
- Жесткий код
list
с числами *tmp
было выделено 16 байт- Скопируйте числа из
list
вtmp
- Освободить список, чтобы в нем не было выделенных байтов
- Список теперь равен tmp
-
Как
list
теперь может быть равно,tmp
когдаlist
у него нет выделенной памяти? -
list
Указывает на адресtmp
? Если да, то почему нам не нужно выделять память дляlist
, поскольку ранее в коде мы делали этоint *tmp = malloc(4 * sizeof(int));
Комментарии:
1. List и tmp — это ссылки, которые указывают на один и тот же адрес памяти. Поскольку вы уже выделили память и назначили ее tmp, ту же самую выделенную память можно использовать для списка. Итак, malloc выделяет память, которая может быть назначена tmp, list или любому количеству указателей.
2. Почему бы не использовать
realloc
?3. Вы можете копировать значения указателя точно так же, как любое другое значение. Обратите внимание, что при этом данные не копируются.
4. @tadman Они привели
realloc
следующий пример после этого примера, но я просто хочу знать ответ на свой вопрос в отношении этого примера.5. @Akshit:
malloc(4 * sizeof(int));
возвращает указатель типаint
не точно:malloc()
возвращает универсальный указатель, который может быть безопасно и автоматически (в C) преобразован в указатель наint
при сохранении наtmp
. В настоящее время это различие выходит за рамки навыков операционной системы, но оно может помочь понять природу указателей: это простые переменные, которые содержат адрес памяти. Их тип определяет, как они разыменовываются и как их значение используется в выражении.
Ответ №1:
*list
было выделено 12 байт (3 * sizeof(int), sizeof(int) = 4
Чтобы быть точным, вы выделили 12 байт памяти и установили list
, чтобы указать на эту память.
Жесткий код
list
с числами
*tmp
было выделено 16 байт
Опять же, чтобы быть точным, вы выделили 16 байт памяти и установили переменную pointer tmp
так, чтобы она указывала на нее.
Скопируйте числа из
list
вtmp
Освободитьlist
, чтобы в ней не было выделенных байтов
Если быть точным, вы освободили объект, на который list
указывалось, так что теперь list
он указывает на мусор и его нельзя разыменовывать.
list
теперь равноtmp
Чтобы быть точным, list
теперь указывает на то же самое, на что tmp
указывает те 16 байт, которые вы выделили, на которые ранее указывал только tmp
.
Как
list
теперь может быть равноtmp
, когда у list нет выделенной памяти?
Ранее list
не указывало на выделенную память. Но вы изменили его, чтобы указать на 16 байт, которые вы выделили вторым. Значение указателя — это то, на что он указывает, list
и tmp
теперь указывают на одно и то же, поэтому они имеют одинаковое значение. Таким образом, теперь они равны.
Указывает ли list на адрес tmp? Если да, то почему нам не нужно выделять память для списка, поскольку ранее в коде мы сделали это int * tmp = malloc(4 * sizeof(int));
Код освобождает первый выделенный блок памяти. Если бы он не выделил второй блок памяти, не было бы ничего допустимого для любого указателя, на который можно было бы указать!
Комментарии:
1. Поскольку
list
ссылается на тот же адрес памяти, что иtmp
, и я хочу освободить память, чтобы избежать каких-либо утечек памяти, должен ли я сделатьfree(list)
илиfree(tmp)
2. @ManavDubey Эти оба передают одно и то же значение
free
, поэтому они делают точно то же самое.3. @ManavDubey: вы можете использовать один или другой, поскольку они передадут один и тот же адрес
free
, но вы не должны делать оба, поскольку второй вызов попытается освободить блок, который уже был освобожден первым вызовом, следовательно, вы получите неопределенное поведение.
Ответ №2:
Когда вы копируете указатель, вы просто копируете значение указателя1:
list = tmp;
Это означает, что list
теперь содержит копию tmp
указателя, или, другими словами, они оба указывают на один и тот же адрес памяти. В этом случае этот адрес является выделением.
Как только они станут идентичными, вы можете ссылаться на любой из них взаимозаменяемо.
1 Конечно, это предполагает, что указатели имеют один и тот же тип, например, int*
на int*
, а не int
на int**
. Вы также можете назначить на void*
и преобразовать обратно позже, это тоже работает.
Ответ №3:
указатель — это тип данных, которому назначаются только адреса памяти соответствующего типа данных, в вашем случае в list = tmp;
вы назначаете первую позицию того блока памяти, который вы создали с помощью int * tmp = malloc (4 * sizeof (int));
, когда вы выполняете назначение списку, он будет указывать на этот адрес памяти. (в вашем случае в начале этого блока памяти).