Освобождение памяти с помощью free




Т еперь рассмотри, как происходит освобождение памяти. Переменная указатель хранит адрес области памяти, начиная с которого она может им пользоваться. Однако, она не хранит размера этой области. Откуда тогда функция free знает, сколько памяти необходимо освободить?

Очевидно, что информация о размере выделенного участка должна где-то храниться. Есть несколько решения этой проблемы.

· 1. Можно создать карту, в которой будет храниться тип и размер выделенного участка. Каждый раз при освобождении памяти компьютер будет обращаться к этим данным и получать информацию о размере.

· 2. Второе решение более распространено. Информация о типе и размере хранится на куче до самих данных. Таким образом, при выделении памяти резервируется места больше и туда записывается информация о выделенном участке. При освобождении памяти функция free "подсматривает", сколько памяти необходимо удалить.

Функция free освобождает память, но при этом не изменяет значение указателя, о чём нужно помнить.

Работа с двумерными и многомерными массивами

Д ля динамического создания двумерного массива сначала необходимо создать массив указателей, после чего каждому из элементов этого массива присвоить адрес нового массива.
Для удаления массива необходимо повторить операцию в обратном порядке - удалить сначала подмассивы, а потом и сам массив указателей.

?

  #include <conio.h> #include <stdio.h> #include <stdlib.h>   #define COL_NUM 10 #define ROW_NUM 10   void main() { float **p = NULL; unsigned i;   p = (float**) malloc(ROW_NUM * sizeof(float*)); for (i = 0; i < ROW_NUM; i++) { p[i] = (float*) malloc(COL_NUM * sizeof(float)); }   //Здесь какой-то важный код for (i = 0; i < ROW_NUM; i++) { free(p[i]); } free(p); }

Сначала мы создаём массив указателей, а после этого каждому элементу этого массива присваиваем адрес вновь созданного массива. Это значит, что можно

· 1. Создавать массивы "неправильной формы", то есть массив строк, каждая из которых имеет свой размер.

· 2. Работать по отдельности с каждой строкой массива: освобождать память или изменять размер строки.

Создадим "треугольный" массив и заполним его значениями

?

  #include <conio.h> #include <stdio.h> #include <stdlib.h>   #define SIZE 10   void main() { int **A; int i, j; A = (int**) malloc(SIZE * sizeof(int*));   for (i = 0; i < SIZE; i++) { A[i] = (int*) malloc((i + 1) * sizeof(int)); }   for (i = 0; i < SIZE; i++) { for (j = i; j > 0; j--) { A[i][j] = i * j; } }   for (i = 0; i < SIZE; i++) { for (j = i; j > 0; j--) { printf("%d ", A[i][j]); } printf("\n"); }   for (i = SIZE-1; i > 0; i--) { free(A[i]); } free(A);   getch(); }

Чтобы создать трёхмерный массив, по аналогии, необходимо сначала определить указатель на указатель на указатель, после чего выделить память под массив указателей на указатель, после чего проинициализировать каждый из массивов и т.д.

Calloc

Ф ункция calloc выделяет n объектов размером m и заполняет их нулями. Обычно она используется для выделения памяти под массивы. Синтаксис

?

void* calloc(size_t num, size_t size);

Realloc

Е щё одна важная функция – realloc (re-allocation). Она позволяет изменить размер ранее выделенной памяти и получает в качестве аргументов старый указатель и новый размер памяти в байтах:

?

void* realloc(void* ptr, size_t size)

Функция realloc может как использовать ранее выделенный участок памяти, так и новый. При этом не важно, меньше или больше новый размер – менеджер памяти сам решает, где выделять память.
Пример – пользователь вводит слова. Для начала выделяем под слова массив размером 10. Если пользователь ввёл больше слов, то изменяем его размер, чтобы хватило места. Когда пользователь вводит слово end, прекращаем ввод и выводим на печать все слова.

?

  #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h>   #define TERM_WORD "end" #define SIZE_INCREMENT 10   void main() { //Массив указателей на слова char **words; //Строка, которая используется для считывания введённого пользователем слова char buffer[128]; //Счётчик слов unsigned wordCounter = 0; //Длина введённого слова unsigned length; //Размер массива слов. Для уменьшения издержек на выделение памяти //каждый раз будем увеличивать массив слов не на одно значение, а на //SIZE_INCREMENT слов unsigned size = SIZE_INCREMENT; int i;   //Выделяем память под массив из size указателей words = (char**) malloc(size*sizeof(char*)); do { printf("%d: ", wordCounter); scanf("%127s", buffer); //Функция strcmp возвращает 0, если две строки равны if (strcmp(TERM_WORD, buffer) == 0) { break; } //Определяем длину слова length = strlen(buffer); //В том случае, если введено слов больше, чем длина массива, то //увеличиваем массив слов if (wordCounter >= size) { size += SIZE_INCREMENT; words = (char**) realloc(words, size*sizeof(char*)); } //Выделяем память непосредственно под слово //на 1 байт больше, так как необходимо хранить терминальный символ words[wordCounter] = (char*) malloc(length + 1); //Копируем слово из буффера по адресу, который //хранится в массиве указателей на слова strcpy(words[wordCounter], buffer); wordCounter++; } while(1);   for (i = 0; i < wordCounter; i++) { printf("%s\n", words[i]); } getch();   for (i = 0; i < wordCounter; i++) { free(words[i]); } free(words); }

Хочу обратить внимание, что мы при выделении памяти пишем sizeof(char*), потому что размер указателя на char не равен одному байту, как размер переменной типа char.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: