Перераспределение памяти для пустой ссылки

#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() «освободит» память указателя.

Если бы я руководствовался этим определением:

  1. *list было выделено 12 байт (3 * sizeof(int) , sizeof(int) = 4
  2. Жесткий код list с числами
  3. *tmp было выделено 16 байт
  4. Скопируйте числа из list в tmp
  5. Освободить список, чтобы в нем не было выделенных байтов
  6. Список теперь равен 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)); , когда вы выполняете назначение списку, он будет указывать на этот адрес памяти. (в вашем случае в начале этого блока памяти).