Скачиваний:
2
Добавлен:
03.01.2024
Размер:
1.96 Mб
Скачать

Динамические двумерные массивы

Например:

int n, m; //n и m – количество строк и столбцов матрицы float **matr; // указатель для массива указателей

matr = (float **) malloc(n*sizeof(float *));

// выделение динамической памяти под массив указателей for (int i=0; i<n; i++)

matr[i] = (float *) malloc(m*sizeof(float));

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

Так как функция malloc (calloc) возвращает нетипизированный указатель void *, то необходимо выполнять его преобразование в указатель объявленного типа.

Освобождение памяти, выделенной под двумерный динамический массив

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

Освобождение памяти, выделенной под двумерный динамический массив, также осуществляется библиотечной функции free, которая предназначена для освобождения динамической памяти.

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

free (ИмяМассива[ЗначениеИндекса]);

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

free (ИмяМассива);

ИмяМассива – идентификатор массива, то есть имя двойного указателя для выделяемого блока памяти.

Например:

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

free (matr[i]); /* освобождает память, выделенную для массива значений */

free (matr); /* освобождает память, выделенную под массив указателей */

Обращение к элементам двумерного динамического массива

Адресация элементов динамического массива осуществляется с помощью индексированного имени.

Синтаксис:

ИмяМассива[ВыражениеТипаКонстанты] [ВыражениеТипаКонстанты];

или

ИмяМассива[ЗначениеИндекса][ЗначениеИндекса];

Например:

mas[5][7]

// индекс задается как константа

sl[i][j]

// индекс задается как переменная

array[4*p][p+5]

// индекс задается как выражение

21

Свободные массивы

С помощью динамического выделения памяти под указатели строк можно размещать т.н. свободные массивы.

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

Преимущество использования свободного массива

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

Фактически свободный массив представляет собой одномерный массив указателей на одномерные массивы данных.

Для размещения в оперативной памяти матрицы со строками разной длины необходимо ввести дополнительный массив m, в котором будут храниться размеры строк.

#include <stdlib.h> int main()

{

int **a; // идентификатор массива int i, j, n, *m;

printf("Введите количество строк: "); scanf("%d", &n);

a = (int**)malloc(n * sizeof(int*)); /* Выделение памяти под указатели на строки: */

m = (int*)malloc(n * sizeof(int)); /* массив кол-ва элементов в строках массива a */

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

{

printf("Введите количество столбцов строки %d: ", i); scanf("%d", &m[i]);

a[i] = (int*)malloc(m[i] * sizeof(int)); /*Выделение памяти под хранение строк */

for (j = 0; j<m[i]; j++)

{ printf("a[%d][%d]= ", i, j); scanf("%d", &a[i][j]);

}

}

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

{

for (j = 0; j<m[i]; j++)

{

printf("%3d ", a[i][j]);

}

printf("\n");

}

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

{

free(a[i]);

}

free(a);

free(m);

getchar(); return 0;

}

22

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

Для динамического создания двумерного массива:

сначала необходимо создать массив указателей;

после чего каждому из элементов этого массива присвоить адрес нового массива.

Для удаления массива необходимо повторить операцию в обратном порядке:

удалить сначала подмассивы;

а потом удалить и сам массив указателей.

#include <stdlib.h>

Пример 1

#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);

// удалить массив указателей

}

 

#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();

}

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

Это значит, что можно:

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

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

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

23

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

Пример 2. Вычислить сумму элементов, лежащих на диагоналях матрицы N x N (обратить внимание на четностьнечетность числа N ). Размер массива должен задаваться пользователем с клавиатуры.

#include <stdlib.h> #include <time.h>

/*объявление функции генерации массива */ void gen (int nn, int a, int b, int ***mas);

/*объявление функции вычисления суммы заданных элементов массива*/

int summa(int nn, int **mas);

// объявление функции вывода массива void out (int nn, int **mas);

int main()

{

int **mass, n; int s;

printf("Enter n: "); scanf("%d", &n);

printf("\nGenerating an array \n"); gen(n, 0, 10, &mass); s=summa(n, mass);

out(n, mass);

printf("\nSum of elements = %d", s); printf("\n");

return 0;

}

void out (int nn, int **mas)

{ //функция вывода массива int i, j;

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

{

for (j=0;j<nn; j++) printf("%4d",mas[i][j]); printf("\n");

free (mas[i]);

}

free (mas);

}

void gen(int nn, int a, int b, int ***mas) /* *** - значение указателя, а не адрес */

{ //функция генерации массива int i,j; srand(time(NULL)*1000);

*mas=(int**)malloc(nn*sizeof(int*)); for (i=0;i<nn;i++)

{ (*mas)[i]=(int*)malloc(nn*sizeof(int)); for (j=0;j<nn;j++)

(*mas)[i][j]=rand()%(b-a)+a;

}

}

int summa(int nn, int **mas)

{ // функция вычисления суммы элементов диагоналей int i,j, sum=0;

for (i=0;i<nn;i++) for (j=0;j<nn;j++)

{ if ((i==j) || (i==nn-j-1)) /* нахождение элементов диагоналей */

sum+=mas[i][j]; /* суммирование элементов диагоналей */

}

return sum;

}

24

Динамические двумерные массивы. Краткие итоги

Ключевые термины:

Двумерный динамический массив – это двумерный массив,

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

Динамический массив – это массив, размер которого заранее не фиксирован и может меняться во время исполнения программы.

Значение указателя на двумерный динамический массив

это адрес массива указателей на одномерные массивы или адрес выделяемой области динамической памяти, если двумерный массив представляется как одномерный.

Тип двумерного динамического массива – это тип элементов массива.

Указатель на двумерный динамический массив – это указатель на массив указателей на одномерные массивы или на начало выделяемого участка динамической памяти, если двумерный массив представляется как одномерный.

Краткие итоги:

При работе с массивами, размер которых заранее не известен, используют динамические массивы.

Под объявлением двумерного динамического массива понимают объявление двойного указателя, то есть объявление указателя на указатель.

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

Работа с двумерными динамическими массивами начинается

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

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

Адресация элементов динамического массива осуществляется

спомощью индексированного имени.

Указатели в Си – это мощный инструмент, позволяющий осуществлять непосредственный доступ к памяти процесса (программы). Пользоваться ими нужно с осторожностью!

Если программе нужна память на этапе выполнения, то она может получить её из кучи, а затем должна вернуть её обратно

25

Динамические двумерные массивы. Краткие итоги

Под двумерным массивом понимается одномерный массив, элементами которого являются одномерные массивы.

Другими словами, это набор однотипных данных, имеющий общее имя, и доступ к элементам которого осуществляется по двум индексам.

Иногда двумерный массив также называют матрицей.

Динамическим массивом называют массив с переменным размером, то есть количество элементов может изменяться во время выполнения программы.

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

(динамического создания двумерного массива ):

вначале нужно распределить память для массива указателей на одномерные массивы (создать массив указателей);

затем выделить память для одномерных массивов

(каждому из элементов первого массива присвоить адрес нового массива).

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

Объявление двумерных динамических массивов

Под объявлением двумерного динамического массива понимают объявление двойного указателя, то есть объявление указателя на указатель.

Синтаксис: Тип **ИмяМассива;

ИмяМассива – идентификатор массива, то есть имя двойного указателя для выделяемого блока памяти.

Тип – тип элементов объявляемого динамического массива. Элементами динамического массива не могут быть функции и элементы типа void.

Например:

int **aray; float **matr;

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

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

а затем в цикле с параметром выделяется память под одномерные массивы.

На рис. ниже представлена схема динамической области памяти, выделенной под двумерный массив:

При выделении динамической памяти размеры массивов должны быть полностью определены.

26

27

Соседние файлы в папке Лекции