Распределите память по мере необходимости в C

Выделение памяти во время работы программы - это способ оптимизации использования памяти в программе C, выделяйте память по мере необходимости.
Без использования динамического распределения памяти мы могли бы присвоить массиву максимальное значение длины. Ограничение этого подхода заключается в том, что распределение памяти не является динамическим, другими словами, если бы мы объявили массив размером 100 int myArray[100] и общее количество элементов было бы больше 100 во время компиляции, то программа фактически сломалась бы.
Создание указателей, достаточно больших для хранения данных во время компиляции, является наиболее эффективным способом выделения памяти в программе на языке C.
Есть 2 места, где данные хранятся в программе на C:
- Стек. Все, что связано с выполнением функции, сохраняется в стеке. Как только функция выполняется и завершается, данные больше не сохраняются и удаляются.
- Куча. Здесь вы, программист, храните память. Память, хранящаяся в куче, не будет удалена и будет сохраняться в течение всего времени существования программы. Удаление памяти из кучи - дело программиста.
При динамическом распределении памяти данные всегда сохраняются в куче.
Маллок
Самый простой и наиболее распространенный способ реализации выделения памяти в программировании на C - использовать функцию malloc(), которая: выделяет динамическую память во время выполнения.
#include <stdlib.h> // Include the standard library int *pMyVar = (int*)malloc(100);
pMyVar теперь указывает на расположение первого байта адреса. Кроме того, malloc(100) возвращает адрес, мы также должны преобразовать его в указатель типа int (int*)malloc(100), потому что malloc по умолчанию возвращает указатель типа void.
Назначение памяти для целого числа
#include <stdio.h>
int main() {
int myInt = 1;
printf("The size of an int is: %lu", sizeof(myInt));
// The size of an int is: 4
}
Это будет работать в 32-битной системе, если мы хотим выделить память для 25 целых чисел:
int *pMyVar = (int*)malloc(100);
Поскольку мы не уверены, какой размер байта находится в системе, в которой запущена программа, мы можем использовать функцию sizeof для определения размера целого числа. Если, например, нам нужно было сохранить 25 чисел в массиве, мы могли бы определить, сколько байтов в целом числе, вызвав: sizeof(int), тогда мы просто умножим результат sizeof(int) на количество требуемых целых чисел:
int *pMyVar = (int*)malloc(25*sizeof(int));
Если запрошенная память не может быть выделена из вызова malloc, то возвращается указатель на значение NULL.
if(!pMyVar) {
// abort...
} else {
// do something...
}
Освобождение памяти с помощью Free ()
В программах на C мы всегда освобождаем память, выделенную в куче, после того, как закончили работу с ней, даже если вы закончили конец программы, всегда освобождает память - память, выделенная в куче, всегда автоматически освобождается, когда программа заканчивается.
free(pMyVar);
Утечки памяти
Утечки памяти возникают, когда мы выделяем память динамически и не сохраняем ссылку на адрес, и поэтому теперь мы не можем освободить эту память. Если, например, мы продолжаем потреблять память, не освобождая ее, в конечном итоге будет израсходована системная память. Это часто происходит в цикле while.
#include <stdlib.h>
int main() {
int *pMyVar = (int*)malloc(25*sizeof(int));
if(!pMyVar) {
// abort...
return 1;
} else {
// do something...
free(pMyVar);
pMyVar = NULL;
return 0;
}
}
Обратите внимание, как мы устанавливаем указатель типа int на NULL после того, как мы закончили использование и освобождение блока памяти из определенного адреса, возвращаемого из pMyVar.
Использование функции Calloc ()
Функция Calloc() выделяет память как количество элементов заданного размера. Основное различие междуMalloc() и Calloc() состоит в том, что Calloc() инициализирует выделенную память так, чтобы все байты были установлены в ноль. Calloc() также возвращает NULL, если память не может быть выделена по какой-либо причине.
Опять же, пример динамического выделения блока памяти для 25 целых чисел:
int *pMyVar = (int)calloc(25, sizeof(int));
Перераспределение памяти с помощью функции realloc ()
Функция realloc() позволяет перераспределить память в существующий выделенный блок памяти, а также сохраняет содержимое области памяти.
pMyVar = (int*)realloc(int, pMyVar); // add a further 10 bytes of memory to the pMyVar's address
Итак, давайте сначала выделим память с помощью malloc(), а затем перераспределим дополнительную память с помощью realloc():
#include <stdlib.h>
int main() {
int *pMyVar = (int*)malloc(25*sizeof(int));
if(!pMyVar) {
// abort...
return 1;
} else {
pMyVar = (int*)realloc(pMyVar, 10);
// do something...
free(pMyVar);
pMyVar = NULL;
return 0;
}
}
Мы даже можем использовать в Mac OSX библиотеку malloc/malloc.h, чтобы узнать фактический размер общих байтов, хранящихся в блоке памяти, по указателю:
#include <stdio.h>
#include <stdlib.h>
#include <malloc/malloc.h>
int main() {
int *pMyVar = (int*)malloc(25*sizeof(int));
if(!pMyVar) {
// abort...
return 1;
} else {
pMyVar = (int*)realloc(pMyVar, 10 * sizeof(int));
// do something...
//The memory block size is always
// at least as large as the allocation it backs, and may be larger.
printf("Total Bytes stored at pMarVar: %lu", malloc_size(pMyVar));
// Total Bytes stored at pMarVar: 48
free(pMyVar);
pMyVar = NULL;
return 0;
}
}