У меня есть 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
и free
в своей программе на C++? Вы должны использовать std::vector
для «динамического массива».
И обобщая: каждый раз, когда вы чувствуете необходимость выполнить явное преобразование в стиле C (приведение в стиле C, например (int *) ...
), вам следует воспринимать это как знак того, что вы, вероятно, делаете что-то неправильно.
Кроме того, для любого указателя или массива p
и индекса i
выражение *(p + i)
в точности равно p[i]
. Использование синтаксиса индексации массива обычно упрощает чтение кода (и его требуется меньше писать).
«rand() % 100
» — ой; 1) не используйте rand()
2) не используйте по модулю для уменьшения значения до диапазона, вы испортите среднее значение, а также сделаете некоторые числа более вероятными, чем другие. У нас есть std::uniform_int_distribution не просто так. Возможно, вы захотите посмотреть это видео: rand() считается вредным.
Вы вызываете 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++ когда-то имели общее наследие, но они превратились в совершенно разные языки.
malloc
(илиcalloc
илиrealloc
) вернул вам указатель; вам следует освободить этот указатель. Кроме того,free
правильно обрабатывает нулевые указатели, поэтому вам не нужно это проверять.