Краткий ответ: Да
Более длинный ответ:
Вы не вызываете free "для переменной", но для значения , хранящегося в переменной.
Чтобы лучше понять, что происходит, может быть лучше представить память как большой массив байтов и визуализировать указатель в виде числового индекса в этом массиве. И на большинстве архитектур, с которыми вы, вероятно, столкнетесь, это именно то, что происходит за кулисами.
Когда вы делаете
void * ptr1 = malloc(50);
malloc
резервирует блок из 50 байтов и возвращает указатель на этот блок. Этот указатель является не чем иным, как числовым индексом, сообщающим нам, где в памяти начинается зарезервированный блок.
Теоретически мы могли бы (на некоторых архитектурах) написать
int ptr1 = (int)malloc(50);
Причины, по которым мы этого не делаем:
sizeof(int)
может быть недостаточно большим, чтобы удерживать указатель
void *
сообщает компилятору, что числовое значение, хранящееся в ptr1
, должно рассматриваться как адрес памяти.
Если мы продолжим смотреть на ваш код:
void * ptr2 = ptr1;
Ничего волшебного здесь не происходит. «Числовое значение», сохраненное в ptr1
, копируется в ptr2
, как если бы ptr1
и ptr2
были обычными целочисленными переменными.
ptr1 = malloc(25);
Здесь вы перезаписываете содержимое ptr1
новым «числовым значением», но старым значением
все еще существует как копия в ptr2
.
free(ptr2);
Здесь вы звоните free
со значением, сохраненным в ptr2
. Это значение, возвращаемое malloc(50)
. free
не волнует, какая переменная содержит это значение / адрес. Нужно только, чтобы значение / адрес указывало на первый байт блока памяти, который был зарезервирован с malloc
.
Теоретически, если бы вы знали, что malloc(50)
вернул значение 0xb00b1e5, вы могли бы сделать
free((void *) 0xb00b1e5);
Но вы не можете с уверенностью предсказать, что malloc
вернется, поэтому не делайте этого.