Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛЕКЦИИ Программирование и основы алгоритмизации...doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.5 Mб
Скачать

Выделение и освобождение динамической памяти

Динамическая память используется тогда, когда велик объем данных, или он становится известным лишь во время выполнения программы.

В файле stdlib.h находятся следующие функции для выделения и освобождения динамической памяти в языке C.

void* malloc(unsigned s); - возвращает указатель на начало выделенной области памяти длиной в s байт; при неудаче возвращает NULL (значение константы NULL равно нулю).

unsigned – это тип unsigned int – два байта, 0..65535.

Пример. char* b; b=(char*)malloc(80); - выделена динамическая память под 80 символов.

void* calloc(unsigned n, unsigned m); - возвращает указатель на начало области обнуленной динамической памяти, выделенной для размещения n элементов по m байт каждый; при неудаче возвращает NULL.

void* realloc(void* b, unsigned ns); - изменяет размер ранее выделенной памяти до ns байт. Если b=NULL (память не выделялась), то выполняется как malloc.

void free(void*b); - освобождает ранее выделенную память, адресуемую b.

В языке C++ динамическое распределение памяти для любых стандартных или пользовательских типов реализуется операциями new и delete.

Операция new автоматически создает объект соответствующего размера и возвращает указатель соответствующего типа. Если new не может найти необходимое пространство в памяти, она возвращает указатель, равный нулю.

int* iptr; iptr=new int;

Объявлен указатель iptr на целое и по этому указателю выделяется динамическая память под целое (лишено практического смысла). Адрес выделенного под целое участка памяти заносится в iptr.

Динамическая память освобождается также по указателю:

delete iptr;

В C++ можно использовать инициализатор для только что созданного в динамической памяти объекта : float* fp = new float(3.14159);

int* ptr; ptr=new int[100];// можно int* ptr=new int[100];

Объявлен указатель ptr на целое и по этому указателю выделяется непрерывный участок динамической памяти под массив на 100 целых чисел. Адрес выделенного участка, т.е. адрес первого его байта, или &ptr[0], заносится в ptr.

Динамическая память, выделенная под массив, освобождается оператором delete[]ptr; При записи delete ptr; динамическая память освобождается только под первым элементом массива, т.е. ptr[0];

Контроль за правильностью выполнения операции выделения динамической памяти осуществляется с помощью макроса assert, определенного в файле <assert.h>. Например,

int n,vptr; // n – размер массива

------------ инициализация n -------------

vptr = new int[n];

assert(vptr!=0);

// инициализация элементов массива случайными числами

// в диапазоне значений от -9 до 9

for(int i=0: i<n; i++)

vptr[i]= (rand()-16383)%10;

--------- обработка динамического массива --------

delete[]vptr;

vptr=0;

Операция new выделяет непрерывный участок динамической памяти под массив длиной n, для целых чисел, и возвращает адрес этого участка, т.е. адрес элемента массива с индексом 0 – vptr[0]. Если память не выделена, то значение указателя vptr окажется равным нулю, а значение выражения vptr!=0 – ложным (нулевым). Тогда макрос assert прерывает выполнение программы. При завершении работы выводится сообщение об ошибке вида: Assertion failed: expression, file <имя файла>, line <номер строки>. После того, как отладка программы будет закончена и макросы assert будут больше не нужны, в начале программы достаточно добавить строку #define NDEBUG вместо того, чтобы удалять в программе каждый макрос assert вручную. Операция delete объявляет участок памяти под массивом свободным. После применения операции delete указатель рекомендуется обнулять, с целью защиты программного продукта.

Выделение и освобождение динамической памяти для размещения двумерного массива (матрицы) выполняется, например, следующим образом.

int n, m, **nptr; // n – число строк, m – число столбцов матрицы

------------ инициализация n, m -------------

// выделение памяти под массив указателей на строки

nptr=new int*[n];

assert(nptr!=0);

for(int i=0; i<n; i++) {

// выделение памяти под i – ю строку

nptr[i]=new int[m];

assert(nptr[i]!=0);

for(int j=0; j<m; j++)

// инициализация строк матрицы случайными

// числами в диапазоне значений от -99 до 99

nptr[i][j] = (rand()-16383)%100;}

------------- обработка динамической матрицы ------------

for(int i=0: i<n; i++)

// освобождение памяти под i – й строкой

delete[]nptr[i];

// освобождение памяти под массивом указателей на строки

delete[]nptr;

nptr=0;

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

int n, m, **mptr; //n – число строк, m – число столбцов матрицы

------------ инициализация n, m -------------

// выделение памяти под массив указателей на столбцы

mptr=new int*[m];

assert(mptr!=0);

for(int j=0; j< m; j++) {

// выделение памяти под j – й столбец

mptr[j]=new int[n];

assert(mptr[j]!=0);

for(int i=0: i<n; i++)

// инициализация столбцов матрицы случайными

// числами в диапазоне значений от -99 до 99

mptr[j][i]= (rand()-16383)%100; }

------------- обработка динамической матрицы ------------

for(int j=0; j<m; j++)

// освобождение памяти под j– м столбцом

delete[]mptr[j];

// освобождение памяти под массивом указателей на столбцы

delete[]mptr;

mptr=0;