Выделение памяти для динамического массива внутри функции
Допустим у меня есть код:
#include <iostream>
using namespace std;
int *foo(int n) {
int *arr = (int *) malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
arr[i] = i;
}
return arr;
}
int main() {
int n = 0; //Длина массива
cin >> n;
int *array = foo(n);
for (int i = 0; i < n; i++) {
cout << array[i] << " ";
}
free(array);
return 0;
}
Эта программа создает массив и выводит его элементы на экран.
Можно ли выделить память для массива внутри функции и вернуть из неё адрес начала массива, но освободить память, используемую массивом, уже в функции main()? Или произойдёт утечка памяти?
Ответы (2 шт):
Да, так можно делать. Компилятор доволен, valgrind пишет что программа отлично работает:
$ g++ -g -std=c++17 -pedantic -Wall -Wextra -Werror -Wwrite-strings -Wconversion temp.cpp $ echo 10 | valgrind ./a.out ==18731== Memcheck, a memory error detector ==18731== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==18731== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==18731== Command: ./a.out ==18731== 0 1 2 3 4 5 6 7 8 9 ==18731== ==18731== HEAP SUMMARY: ==18731== in use at exit: 72,704 bytes in 1 blocks ==18731== total heap usage: 4 allocs, 3 frees, 77,864 bytes allocated ==18731== ==18731== LEAK SUMMARY: ==18731== definitely lost: 0 bytes in 0 blocks ==18731== indirectly lost: 0 bytes in 0 blocks ==18731== possibly lost: 0 bytes in 0 blocks ==18731== still reachable: 72,704 bytes in 1 blocks ==18731== suppressed: 0 bytes in 0 blocks ==18731== Rerun with --leak-check=full to see details of leaked memory ==18731== ==18731== For counts of detected and suppressed errors, rerun with: -v ==18731== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
P.S. Не обращайте внимание на "still reachable: 72,704 bytes in 1 blocks". Это память выделенная стандартной библиотекой С++. Она есть даже если запускать программу с пустым main.
Не очень понятно, почему вообще появилось сомнение, что выделение памяти и её освобождение в разных функциях может приводить к каким-то утечкам.
Собственно, подобным образом работают все классы (если речь всё же о C++), которые выделяют в конструкторе (условная функция №1) память в куче, и освобождают её в деструкторе (функция №2).
Если речь про C (на что намекает пара malloc/free), то так же не должно быть каких-либо сомнений с выделением в одной функции, и освобождением в другой. Главное, не потерять полученный при выделении указатель и использовать его в том же виде при освобождении. Ну и, конечно же, не допускать попытку повторного освобождения памяти, что является серьёзной ошибкой. В качестве защиты от такого практикуется обнуление указателя после освобождения памяти, т.к. вызов free(NULL) вполне легален и просто ничего не делает:
T* p = malloc(size);
...
free(p);
p = NULL;
Однако, в случае, если p передаётся по значению в функцию, где производится освобождение, обнуление будет лишено смысла, т.к. просто обнулится локальная переменная. Чтобы подобная защита продолжала работать надо передавать указатель на переменную, хранящую адрес выделенной памяти, т.е. "указатель на указатель".