====== stdlib.h ======
===== Управление динамической памятью =====
==== malloc ====
прототип: ''void *malloc(unsigned s);''
Функция malloc() выделяет память длиной для определенного количества байт и возвращает указатель на начало выделенной памяти. Через полученный указатель мы можем помещать данные в выделенную память. Рассмотрим простой пример:
#include
#include // для подключения функции malloc
int main(void) {
int *ptr = malloc(sizeof(int)); // выделяем память для одного int
if(ptr != NULL) {
*ptr = 24; // помещаем значение в выделенную память
printf("%d \n", *ptr);
}
free(ptr);
ptr = NULL;
}
Немотря на освобождение памяти с помощью функции free() указатель сохраняет свой адрес, и теоретически мы можем обращаться к памяти по данному указателю. Однако полученные значения уже будут неопределенными и недетеминированными. Поэтому некоторые советуют после освобождения памяти также устанавливать для указателя значение NULL
++++выделение памяти под массив|
#include
#include
int main(void) {
int n = 4;
int *ptr = malloc(n * sizeof(int)); // выделяем память для 4-х чисел int
if(ptr) {
// помещаем значения в выделенную память
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;
ptr[3] = 5;
// получаем значения
for(int i = 0; i < n; i++) {
printf("%d", ptr[i]);
}
}
free(ptr);
}
++++
++++выделение памяти под структуру|
#include
#include
struct person{
char* name;
int age;
};
int main(void) {
// выделяем память для одной структуры person
struct person *ptr = malloc(sizeof(struct person));
if(ptr) {
// помещаем значения в выделенную память
ptr->name = "Tom";
ptr->age = 38;
// получаем значения
printf("%s : %d", ptr->name, ptr->age); // Tom : 38
}
free(ptr);
return 0;
}
++++
==== calloc ====
прототип: ''void *calloc(unsigned n, unsigned m);''
Она выделяет память для n элементов по m байт каждый и возвращает указатель на начало выделенной памяти. В случае неудачного выполнения возвращает NULL
В отличие от функции malloc() она инициализирует все выделенные байты памяти нулями.
==== realloc ====
прототип: ''void *realloc(void *bl, unsigned ns);''
Первый параметр представляет указатель на ранее выделенный блок памяти. А второй параметр представляет новый размер блока памяти в байтах.
Если указатель bl имеет значение NULL, то действие функции аналогично действию malloc
#include
#include
int main(void) {
// выделяем память для 1-го объекта int
int size = sizeof(int);
int *ptr = malloc(size);
if(ptr) {
// отображаем адрес и размер памяти
printf("Addresss: %p \t Size: %d\n", (void*)ptr, size);
}
// расширяем память до размера 4-х объектов int
size = 4 * sizeof(int);
int *ptr_new = realloc(ptr, size);
// если выделение памяти прошло успещно
if(ptr_new) {
printf("Reallocation\n");
// заново отображаем адрес и размер памяти
printf("Addresss: %p \t Size: %d\n", (void*)ptr_new, size);
free(ptr_new); // освобождаем новый указатель
} else {
free(ptr); // освобождаем старый указатель
}
}
==== free ====
Имеет прототип: ''void *free(void *bl);''
Освобождает ранее выделенный блок памяти, на начало которого указывает указатель bl.
Расмотрим, когда нужно освобождать память:
* Указатель определен в блоке кода. В этом случае указатель будет доступен только в пределах данного блока кода. Соответственно память необходимо освобождать при выходе из этого блока.
* Указатель определен как статический объект. В этом случае динамическая память выделяется один раз и доступна через указатель при каждом повторном входе блок. В этом случае память нужно освобождать только после завершения ее использования.
* Указатель является глобальным объектом по отношению к блоку. В этом случае динамическая память доступна во всех блоках, где доступен указатель, а память нужно освобождать только после завершения ее использования.