Динамическое выделение памяти в C: освоение malloc, calloc, realloc и free
Динамическое выделение памяти в C
Это руководство проведет вас через динамическое выделение памяти в C с использованием стандартных функций библиотеки malloc(), calloc(), realloc() и free(), с понятными примерами и лучшими практиками.
Зачем использовать динамическое выделение?
Статические массивы имеют фиксированный размер, объявленный во время компиляции, что может привести к нерациональному расходу памяти или недостаточной емкости во время выполнения. Динамическое выделение позволяет запрашивать ровно столько памяти, сколько нужно, пока программа работает.
Все четыре функции определены в заголовочном файле <stdlib.h> и предоставляют контролируемый способ управления памятью кучи.
malloc() — выделение блока байтов
Название malloc расшифровывается как «memory allocation». Она резервирует непрерывный блок памяти указанного размера (в байтах) и возвращает указатель типа void *, который можно привести к любому другому типу указателя.
Синтаксис
ptr = malloc(size_in_bytes); // приведение к нужному типу при необходимости
Пример
float *ptr = malloc(100 * sizeof(float)); // 400 байт на большинстве систем
Здесь ptr указывает на первый байт блока в 400 байт. Если запрос не удается, malloc возвращает NULL. Рекомендуется избегать ненужных приведений в C; компилятор может вывести тип при присваивании результата типизированному указателю.
calloc() — выделение и обнуление
calloc означает «contiguous allocation». В отличие от malloc, она инициализирует каждый бит выделенного блока нулями, что делает ее безопасной для числовых типов и указателей.
Синтаксис
ptr = calloc(num_elements, size_of_each_element);
Пример
float *ptr = calloc(25, sizeof(float)); // 25 обнуленных элементов float
Возвращаемый указатель равен NULL, если выделение не удалось.
free() — освобождение выделенной памяти
Память, полученная с помощью malloc или calloc, сохраняется до явного освобождения. free() деаллоцирует блок и возвращает память в кучу для повторного использования.
Синтаксис
free(ptr);
Вызов free для NULL указателя безопасен и ничего не делает.
Пример 1: Использование malloc() и free()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("Enter number of elements: ");
scanf("%d", &n);
ptr = malloc(n * sizeof(int));
if (!ptr) {
fprintf(stderr, "Error: memory not allocated.\n");
return EXIT_FAILURE;
}
printf("Enter elements: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
Вывод
Enter number of elements: 3
Enter elements: 100 20 36
Sum = 156
Пример 2: Использование calloc() и free()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("Enter number of elements: ");
scanf("%d", &n);
ptr = calloc(n, sizeof(int));
if (!ptr) {
fprintf(stderr, "Error: memory not allocated.\n");
return EXIT_FAILURE;
}
printf("Enter elements: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
Вывод
Enter number of elements: 3
Enter elements: 100 20 36
Sum = 156
realloc() — изменение размера существующего выделения
Если вы обнаружите, что текущее выделение слишком мало или больше необходимого, realloc() корректирует размер, сохраняя существующие данные (до нового размера).
Синтаксис
ptr = realloc(ptr, new_size_in_bytes);
Она возвращает указатель на перераспределенный блок или NULL при неудаче. Чтобы избежать утечек памяти, сохраняйте результат во временном указателе.
Пример 3: Использование realloc()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *ptr, i, n1, n2;
printf("Enter initial size: ");
scanf("%d", &n1);
ptr = malloc(n1 * sizeof(int));
if (!ptr) {
fprintf(stderr, "Allocation failed.\n");
return EXIT_FAILURE;
}
printf("Addresses before reallocation:\n");
for (i = 0; i < n1; ++i) printf("%p\n", ptr + i);
printf("\nEnter new size: ");
scanf("%d", &n2);
int *tmp = realloc(ptr, n2 * sizeof(int));
if (!tmp) {
fprintf(stderr, "Reallocation failed.\n");
free(ptr);
return EXIT_FAILURE;
}
ptr = tmp;
printf("Addresses after reallocation:\n");
for (i = 0; i < n2; ++i) printf("%p\n", ptr + i);
free(ptr);
return EXIT_SUCCESS;
}
Типичный вывод
Enter initial size: 2
Addresses before reallocation:
0x7ffc12345670
0x7ffc12345674
Enter new size: 4
Addresses after reallocation:
0x7ffc12345670
0x7ffc12345674
0x7ffc12345678
0x7ffc1234567c
Освоив эти четыре функции и применяя правильную обработку ошибок, вы сможете безопасно и эффективно управлять памятью кучи в любом приложении на C.
Язык C
- Понимание ROM, PROM, EPROM и EEPROM: дизайн, программирование и идентификация
- Микропроцессоры: эволюция вычислений с запрограммированной памятью
- Управление памятью в C++: экспертное использование new и delete
- Cervoz представляет DDR4-2666 для промышленных AI и IoT решений
- Динамическое выделение массивов в C++: практическое руководство с примерами кода
- calloc() в C: выделение обнулённой памяти и практический пример
- Использование realloc() в C: синтаксис, лучшие практики и пример
- Динамическое управление памятью в C: malloc, calloc, realloc, free
- Динамическое ценообразование возвращается в традиционный ритейл: почему это неизбежно
- Динамическая память в C++: стек против кучи