Как освободить память для массива, выделенного malloc?

У меня есть 2 варианта кода:

1-й:

void PrintMem(const int* memarr,const size_t size) {
    for (size_t index = 0; index < size; ++index) {
        std::cout << '<'<<(index+1)<<"> "s<<*(memarr + index) << std::endl;
    }
}

void FillMem(int* memarr, const size_t size) {
    srand(time(0));
    for (size_t index = 0; index < size; ++index) {
        *(memarr + index) = rand() % 100;
    }
}

int main() {
    const int size_iter = 10000000;
    int n = 30;
    int* ptr = nullptr;
    int size = size_iter;
    for (int i = 1; i <= n; ++i) {
        size = size_iter * i;
        if (i == 1) {
            ptr = (int*)malloc(size * sizeof(int));
        }
        else {
            ptr = (int*)realloc(ptr, size * sizeof(int));    
        }
        if (ptr == nullptr) {
            printf("memory allocation error\n");
            break;
        }
        std::cout << '[' << i << ']';
        printf(" address: %p", (void*)ptr);
        std::cout << ", size: "s << size;
        std::cout << " *********************" << std::endl;
        FillMem(ptr, size);
        //PrintMem(ptr, size);

    }
    if (ptr != nullptr) {
        free(ptr);
    }
}

2-й:

void PrintMem(const int* memarr,const size_t size) {
    for (size_t index = 0; index < size; ++index) {
        std::cout << '<'<<(index+1)<<"> "s<<*(memarr + index) << std::endl;
    }
}

void FillMem(int* memarr, const size_t size) {
    srand(time(0));
    for (size_t index = 0; index < size; ++index) {
        *(memarr + index) = rand() % 100;
    }
}

int main() {
    const int size_iter = 10000000;
    int n = 30;
    int* ptr = nullptr;
    int size = size_iter;
    for (int i = 1; i <= n; ++i) {
        size = size_iter * i;
        int* new_ptr = nullptr;
        if (i == 1) {
            new_ptr = (int*)malloc(size * sizeof(int));
        }
        else {
            new_ptr = (int*)realloc(ptr, size * sizeof(int));    
        }
        if (new_ptr == nullptr) {
            printf("memory allocation error\n");
            break;
        }
        ptr = new_ptr;
        std::cout << '[' << i << ']';
        printf(" address: %p", (void*)ptr);
        std::cout << ", size: "s << size;
        std::cout << " *********************" << std::endl;
        FillMem(ptr, size);
        //PrintMem(ptr, size);

    }
    if (ptr != nullptr) {
        free(ptr);
    }
}

Как правильно освободить память массива?

if (ptr != nullptr) {
    free(ptr);
}

или:

if (ptr != nullptr) {
    for (int i = 0; i < size; ++i) {
        free((ptr + i));
   }
   free(ptr);
}

Я попробовал оба варианта.

Я думаю, что второй вариант с int* new_ptr будет лучше, потому что он, по крайней мере, сохранит предыдущую итерацию изменения размера памяти.

Мне просто нужно знать, как это оптимизировать, и правильно ли освобождать только ptr или мне нужно освобождать каждый блок памяти?

malloc (или calloc или realloc) вернул вам указатель; вам следует освободить этот указатель. Кроме того, free правильно обрабатывает нулевые указатели, поэтому вам не нужно это проверять.
Pete Becker 24.06.2024 19:17

Почему вы используете malloc и free в своей программе на C++? Вы должны использовать std::vector для «динамического массива».

Some programmer dude 24.06.2024 19:21

И обобщая: каждый раз, когда вы чувствуете необходимость выполнить явное преобразование в стиле C (приведение в стиле C, например (int *) ...), вам следует воспринимать это как знак того, что вы, вероятно, делаете что-то неправильно.

Some programmer dude 24.06.2024 19:22

Кроме того, для любого указателя или массива p и индекса i выражение *(p + i) в точности равно p[i]. Использование синтаксиса индексации массива обычно упрощает чтение кода (и его требуется меньше писать).

Some programmer dude 24.06.2024 19:24

«rand() % 100» — ой; 1) не используйте rand() 2) не используйте по модулю для уменьшения значения до диапазона, вы испортите среднее значение, а также сделаете некоторые числа более вероятными, чем другие. У нас есть std::uniform_int_distribution не просто так. Возможно, вы захотите посмотреть это видео: rand() считается вредным.

Jesper Juhl 25.06.2024 01:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы вызываете malloc() только один раз, чтобы создать массив, и вызываете realloc() несколько раз, чтобы перераспределить массив. Существует только один массив, поэтому вам нужно вызвать free() только один раз, чтобы освободить этот массив. Не пытайтесь free() обрабатывать отдельные элементы, поскольку они не malloc обрабатывались индивидуально. По одному free() за каждый успешный malloc()/realloc().

Кроме того, вам не нужно проверять nullptr перед вызовом free(), поскольку он уже обрабатывает это внутри себя.

Кроме того, в случае сбоя realloc() исходный массив остается нетронутым, но вы безоговорочно перезаписываете переменную ptr, поэтому вы потеряете существующий массив. Вам необходимо проверить наличие сбоя realloc(), прежде чем переназначать переменную ptr.

Кстати, еще несколько мелких придирок к оставшемуся коду:

  • Вместо memarr[index] следует использовать *(memarr + index).

  • не звоните srand() несколько раз. Позвоните один раз в main().

  • "> "s должно быть просто "> ", нет необходимости заставлять его std::string просто печатать, поскольку operator<< прекрасно справляется со строковыми литералами (как видно из некоторых других ваших отпечатков).

  • не следует смешивать printf() с std::cout. Придерживайтесь того или другого.

Вместо этого попробуйте что-нибудь подобное:

void PrintMem(const int* memarr, const size_t size) {
    for (size_t index = 0; index < size; ++index) {
        std::cout << '<' << (index+1) << "> " << memarr[index] << '\n';
    }
}

void FillMem(int* memarr, const size_t size) {
    for (size_t index = 0; index < size; ++index) {
        memarr[index] = rand() % 100;
    }
}

int main() {
    srand(time(0));
    const int size_iter = 10000000;
    int n = 30;
    int* ptr = nullptr;
    for (int i = 1; i <= n; ++i) {
        int size = size_iter * i;
        if (i == 1) {
            ptr = static_cast<int*>(malloc(size * sizeof(int)));
            if (ptr == nullptr) {
                std::cerr << "memory allocation error\n";
                break;
            }
        }
        else {
            int *new_ptr = static_cast<int*>(realloc(ptr, size * sizeof(int)));
            if (new_ptr == nullptr) {
                std::cerr << "memory reallocation error\n";
                break;
            }
            ptr = new_ptr;
        }
        std::cout << '[' << i << ']';
        std::cout << " address: " << static_cast<void*>(ptr);
        std::cout << ", size: " << size;
        std::cout << " *********************\n";
        FillMem(ptr, size);
        //PrintMem(ptr, size);
    }
    free(ptr);
}

При этом вам вообще не следует использовать malloc/realloc() в C++. Вместо этого используйте std::vector, и пусть он обрабатывает память за вас, например:

#include <vector>

void PrintMem(const std::vector<int> &arr) {
    for (size_t index = 0; index < arr.size(); ++index) {
        std::cout << '<' << (index+1) << "> " << memarr[index] << '\n';
    }
}

void FillMem(std::vector<int> &arr) {
    for (size_t index = 0; index < arr.size(); ++index) {
        memarr[index] = rand() % 100;
    }
}

int main() {
    srand(time(0));
    const int size_iter = 10000000;
    int n = 30;
    std::vector<int> arr;
    for (int i = 1; i <= n; ++i) {
        int size = size_iter * i;
        arr.resize(size);
        std::cout << '[' << i << ']';
        std::cout << " address: " << static_cast<void*>(arr.data());
        std::cout << ", size: " << size;
        std::cout << " *********************\n";
        FillMem(arr);
        //PrintMem(arr);
    }
}

Вам также следует рассмотреть возможность использования генератора случайных чисел в стиле C++ из библиотеки <random> вместо использования генератора случайных чисел в стиле C rand().

Также рассмотрите возможность использования циклов range-for и стандартных алгоритмов , таких как std::for_each() , std::generate() и т. д.

Короче говоря, по возможности избегайте использования C-измов в C++. Возможно, C и C++ когда-то имели общее наследие, но они превратились в совершенно разные языки.

Другие вопросы по теме