Содержание

Операторы динамического распределения памяти С++

Операторы динамического распределения памяти: new(), delete(); malloc(), free().

В языке С++ предусмотрены два оператора динамического распределения памяти: new и delete. Эти операторы выделяют и освобождают память в ходе выполнения программы. Динамическое распределение памяти представляет собой важную часть практически всех реальных программ. В языке С++ есть альтернативный способ динамического распределения памяти, основанный на функциях malloc() и free(). Они сохранены для того, чтобы достичь совместимости с языком С. Однако в программах на языке С++ следует применять операторы new и delete, поскольку они имеют ряд важных преимуществ: во-первых, оператор new автоматически выделяет количество памяти, необходимое объекту указанного типа (оператор Операция sizeof теперь применять не следует), во-вторых, оператор new автоматически возвращает указатель заданного типа. Также операторы new и delete можно перегружать, что позволяет создавать настраиваемые системы для выделения динамической памяти.

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

Общее определение операторов new и delete

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

/* 
 * File:   
 * Author: darkfire
 *
 * Created on September 15, 2010, 6:32 PM
 */

#include <iostream>
#include <ctime>
#include <stdlib.h>

using namespace std;

const int SIZE = 7;

int main () {
    srand(time(NULL));
    int *parr = new int [SIZE]; // Определили указатель. Выделили память для массива.
    int *parr0 = parr; //сохранили для дальнейшего использования адресс массива.

    for (int i=0;i<SIZE-1;i++){
		*parr=rand()%100;
		cout<<*parr<<"\n";
		parr++;
    }
    parr = parr0;
    
    for (int i=0;i<SIZE-1;i++){
        cout<<*parr<<"\n";
        parr++;
    }
    parr = parr0;/* если указателю не присвоить адресс первого элемента массива
                  * оператор делете будет выводить ошибку.
    */
    delete [] parr;

}

Многомерные динамические массивы

Многомерный массив в C по своей сути одномерен. Операции new и delete позволяют создавать и удалять динамические массивы, поддерживая при этом иллюзию произвольной размерности. Деятельность по организации динамического массива требует дополнительного внимания, которое окупается важным преимуществом: характеристики массива (операнды операции new) могут не быть константными выражениями. Это позволяет создавать многомерные динамические массивы произвольной конфигурации.

Следующий пример иллюстрирует работу с динамическими массивами.

#include <iostream>
using namespace std;
 
 void main()
 {
 	int i, j;

	 // Переменные для описания характеристик массивов.
	 int m1 = 5, m2 = 5;

	 /*
	 Организация двумерного динамического массива производится в два этапа.
	 Сначала создаётся одномерный массив указателей, а затем каждому элементу
 	 этого массива присваивается адрес одномерного массива. Для характеристик
	 размеров массивов не требуется константных выражений.
	 */
	 int **pArr = new int*[m1];
	 for (i = 0; i < m1; i++) 
		pArr[i] = new int[m2];

	 pArr[3][3] = 100;
	 cout << pArr[3][3] << "\n";

 	//Последовательное уничтожение двумерного массива…
	
	 for (i = 0; i < m1; i++) 
		delete[]pArr[i];
	 delete[]pArr;
}

Алгоритм изменения размера динамического массива

Например, мы хотим увеличить размер уже существующего динамического массива на 1.

  1. Создаем новый динамический массив с размерность на единицу больше от существующего массива.
  2. Копируем все данные из старого массива в новый массив.
  3. Добавляем значение нового элемента массива.
  4. Удаляем старый массив. (Может понадобиться изменить переменную размерности массива, например если размерность указывалась через глобальную переменную).
  5. Присваиваем старому указателю адрес нового массива.

Примеры на многомерные динамические массивы

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

#include <iostream>
using namespace std;

void main()
{
	int i, j;

	// Переменные для описания характеристик массивов.
	int m1 = 5, wm = 5;
	int **pXArr = new int*[m1];

	for (i = 0; i < m1; i++, wm--) 
		pXArr[i] = new int[m1];

	
	//Заполнение массива нулями и показ его на экран
	for (i = m1 - 1; i >= 0; i--, wm++) {
		for (j = 0; j < wm; j++){
			pXArr[i][j]=0;
			cout<<pXArr[i][j]<<"\t";
		}
		cout<<"\n\n";
	}

	//Последовательное уничтожение двумерного массива треугольной конфигурации…

	for (i = 0; i < m1; i++) 
		delete[]pXArr[i];
	delete[]pXArr;
}

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

 #include <iostream>
using namespace std;

void main()
{
	int i, j;

	// Переменные для описания характеристик массивов.
	int m1 = 5, m2 = 5, m3 = 2;
	
	// указатель на указатель на указатель :)
	int ***ppArr;

	// Создание массива
	ppArr = new int**[m1];
	for (i = 0; i <m1; i++) 
		ppArr[i] = new int*[m2];

	for (i = 0; i < m1; i++)
		for (j = 0; j < m2; j++) 
			ppArr[i][j] = new int[m3];
	
	ppArr[1][2][3] = 750; 
	cout << ppArr[1][2][3] << "\n"; 

	// Удаление в последовательности, обратной созданию
	for (i = 0; i < m1; i++)
		for (j = 0; j < m2; j++) 
			delete[]ppArr[i][j];

	for (i = 0; i < m1; i++) 
		delete[]ppArr[i];
	delete[] ppArr;
}