Функции управления динамической памятью дают возможность легко управлять памятью.
Они являются функциями библиотеки общего назначения.
Объявления этих функций находится в заголовочном файле <stdlib.h>, поэтому в программах, использующих эти функции, необходимо включать следующую директиву препроцессора:
#include <stdlib.h>
Выделение памяти
void * malloc(size_t size)
Функция выделяет память размером size и возвращает адрес начала области памяти. При присвоении указателю происходит явное преобразование типа. Выравнивание границы происходит автоматически, но выделенная память не инициируется нулями.
void realloc (void *block, size_t size)
Функция делает размер блока по указателю block равным size байтов и возвращает указатель на блок, возможно перемещенный. В случае перемещения блока данные из исходного блока копируются в новый блок, освобождая исходный блок.
void * сalloc(size_t nelem, size_t elsize)
Функция выделяет блок, который вмещает nelem элементов размером elsize байтов каждый, возвращает адрес начала области памяти. Выделенная память инициируется нулями.
У каждого блока памяти есть байты, где хранятся длина блока и признак того, занят он или свободен. Эти функции управления памятью используют системные вызовы brk и sbrk. Когда функциям malloc, сalloc и realloc нужно изменить границу выделяемой памяти, они обычно делают это с запасом. Если будущим запросам хватает выделенного пространства, они не используют системный вызов. Так библиотечные функции минимизируют число выполнения системных вызовов.
Если вызов функции закончился неуспешно, то она возвращает значение NULL.
Освобождение памяти
void free(void *block)
Функция освобождает блок памяти по указателю *block и делает его доступным для последующих выделений памяти. Указатель должен указывать на блок, полученный ранее вызовом malloc, calloc или realloc.
Функция free() никогда не возвращает память назад ядру. Вместо этого она устанавливает признак того, что блок свободен. Будущие запросы выделения памяти ищут среди всех свободных блоков блок подходящего размера, прежде чем использовать системный вызов увеличения памяти. Смежные свободные блоки сливаются во время поиска для их более эффективного переиспользования.
Пример 1
int *a;
if ((a=(int *)malloc(sizeof(int)))==NULL) /* выделение памяти под целое типа int*/
{
printf("Не хватает памяти для числа.");
exit(1);
}
*a=-244;
*a+=10;
free(a); /* освобождение памяти*/
Пример 2
struct node {
int data;
struct node *next;
};
struct node *pnode;
if ((pnode = malloc(sizeof(struct node)))==NULL) /* выделение памяти под структуру node*/
{
printf("Не хватает памяти для структуры.");
exit(1);
}
pnod->data=100;
pnod->next=NULL;
Пример 3
int *array;
/* выделение памяти под массив из 3 элементов типа int*/
/*элементы массива равны 0*/
if ((array = calloc(3, sizeof(int)))==NULL) /* выделение памяти под структуру node*/
{
printf("Не хватает памяти для массива.");
exit(1);
}
for (i=0; i<3; i++, array++)
*array=i+1;
Пример 4
struct node {
int data;
struct node *next;
};
struct node *table;
if ((table = calloc(3, sizeof(struct node)))==NULL)
{
printf("Не хватает памяти для массива структур.");
exit(1);
}
Выделяется память под массив из трех элементов структур node. Ссылаться на элементы можно как
в любом другом массиве.
table[2].data = 3;
Пример 5
Вставка узла в список структур
struct node {
int data;
struct node *next;
};
struct node *insert (struct node *p, int i) /*вставка узла после узла *P*/
{struct node *q;
if ((q= malloc(sizeof(struct node)))==NULL)
{
printf("Не хватает памяти для структуры.");
exit(1);
}
q->next = p->next;
q->data = i;
p->next = q;
return (g);
}
Пример 6
Уничтожение узла в списке структур
void delete (struct node *p)
{ struct node *q;
q = p->next;
p->data=q->data;
p->next=q->next;
free (q);
}
Эта функция уничтожает данные, содержащиеся в узле с указателем p. Данные в узле с указателем q копируются в узел с указателем p. Потом узел q уничтожается. Чтобы этот алгоритм уничтожения работал со всеми узлами, включая последний в списке, пустой список должен содержать голову head и узел с нулевым указателем в поле next. Другими словами, последний узел является ограничителем и его нельзя уничтожать. Поэтому в программу надо включить следующую проверку:
if(p->next==NULL) return;