Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КИТ. Лекции за I сем.doc
Скачиваний:
9
Добавлен:
13.11.2018
Размер:
1.36 Mб
Скачать

18.2. Создание одномерного динамического массива.

В языке С размерность массива при объявлении должна задаваться константным выражением. При необходимости работы с массивами перемен­ной размерности нужно объявить вместо массива указатель требуемого типа, а затем в момент необходимости выделить память под массив нужного размера. Таким образом, размер массива в любом случае должен быть указан до начала работы с ним; но при динамическом выделении памяти он указывается не в тексте программы, а непосредственно при захвате памяти, и поэтому может определяться значением переменной.

Формат операции new для массивов:

указатель = new тип [количество] ;

Результат операции new, присваиваемый указателю – адрес начала области памяти для размещения данных указанного количества и типа. При нехватке памяти – результат NULL.

Формат операции delete:

delete указатель;

либо: delete [] указатель; (эти записи равносильны)

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

Пример:

...

double *x;

int i, n;

...

puts(" Введите размер массива: ");

scanf(“%d”, &n);

x = new double [n] ;

if (x == NULL) {

puts(" Предел размерности ! ");

return;

}

for (i=0; i<n; i++) // Ввод элементов массива

scanf(“%lf”, &x[i]); // Косвенная адресация

...

delete [ ]x; // Освобождение памяти

...

18.3. Создание двуxмерного динамического массива.

Операция new способна выделить память лишь под одномерный массив. А как быть, если массив двумерный?

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

Пример. Создать динамическую матрицу размера n1 х n2. Присвоить каждому ее элементу значение, равное сумме номеров его строки и столбца:

...

int **m, n1, n2;

puts("Vvedite chislo strok i stolbtsov");

scanf(“%d%d”, &n1, &n2);

m = new int * [n1]; // Захват памяти для массива указателей -

// на рисунке А (n1=3)

for ( int i=0; i<n1; i++) // Захват памяти для каждого из

m[i] = new int [n2]; // массивов элементов (n1 таких массивов)

// - на рисунке B (n2=4)

. . .

for ( i=0; i<n1; i++)

for ( j=0; j<n2; j++)

m[i][j] = i+j; // *(*(m+i)+j) = i+j;

. . .

for ( i=0; i<n1; i++) // Освобождение памяти

delete m[i];

delete m;

. . .

Устройство полученной "динамической матрицы" изображено на Рис. 19.1. Здесь имеется вспомогательный массив из 3 указателей и 3 массива для хранения данных, в каждом - по 4 элемента. Указатель m указывает на массив указателей, а каждый из указателей - на свою строку матрицы:

Ука­за­тели

m[0]

m[0][0]

m[0][1]

m[0][2]

m[0][3]

m[i][j] ↔ *(*(m+i)+j)

m[1]

m[1][0]

m[1][1]

m[1][2]

m[1][3]

m[2]

m[2][0]

m[2][1]

m[2][2]

m[2][3]

(А) (В)

Рис. 4

Несмотря на сложность полученной схемы, работа с ней предельно проста. Обращение к элементу матрицы имеет точно такой же вид, как и к элементу "обычного" двумерного массива:

m[i][j]

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

m = new int * [n1]; // Выделение памяти

for ( int i=0; i<n1; i++)

m[i] = new int [n2];

. . .

for ( i=0; i<n1; i++) // Освобождение памяти

delete m[i];

delete m;

Преимущества динамических матриц:

  1. Ее размер ограничен лишь размером доступной в данный момент памяти;

  2. Под динамическую матрицу выделяется не больше памяти, чем требуется;

  3. Ее строки могут быть не только одинаковой, но и разной длины (если нужно);

  4. Чтобы поменять местами ее строки, не обязательно выполнять поэлементный обмен в цикле. Можно вместо этого переприсвоить указатели:

int *w=m[0];

m[0]=m[1];

m[1]=w;

Хотя все элементы матрицы остались на месте, 0-ая и 1-ая строки всё же поменялись местами, т.к. m[0] указывает теперь на бывшую 1-ую строку (и наоборот), и значение m[0][i] будет таким, каким до обмена было m[1][i].