Данная статья посвящена тем, кто недавно только начал изучать С (С++). Здесь я хочу более или менее понятно объяснить то, как создавать динамические массивы на примере одно- и двумерных массивов, показать из связь с указателями. Итак, классическое задание - создать динамический массив. Кто не сталкивался с этим в начале изучени языка? Поехали...
Как должно быть уже известно, имя масива фактически является указателем на первый элемент.
Т.е. если имеем
И если теперь записать
то в x запишется значение первого элемента массива
К элементу массива мы можем обращаться как с помощью индекса Arr[i],так и с помощью указателя *(Arr+i), либо в нашем случае еще и *(ptrArr+i). Выражение Arr[i] автоматически преобразуется к *(Arr+i).
После такого вступления мы уже можем создать динамический массив. Для этого будем использовать функцию выделения памяти calloc(), которая имеет следующий прототип
Функция выделяеи num*size байтов и возвращает указатель на первый элемент выделенной области либо null, если выделит память невозможно. Для использования необходимо подключить заголовок
Создадим динамический массив на 10 элементов:
Как видно из примеры, мы взяли указатель и выделили под него память на 10 int-значений. Вот так просто создаются одномерные массивы.
Теперь перейдем к двумерным. Пусть нам требуется создать массив 3*4 (3 строки, 4 столбца).
Двумерный массив мы можем представить как "массив одномерных массивов", т.е. как одномерный массив, элементами которого являеются так же одномерные массивы. Далее, следует, если у нас будет несколько массивов (элементов), стало быть для каждого из них должен быть свой указатель, а это уже получается, что мы должны иметь массив указателей. Этот массив указателей очевидно одномерный и надо его создать, а создавать одномерные динамические массивы мы уже умеем. Но тут есть дно "но"!
В предыдущем примере мы заводили массив int-элементов и указатель int* на первый элемент, а здесь у нас элементами являются указатели на int - int*, и тогда указатель на первый элемент у нас будет уже указателем на ... указатель! т.е. будет иметь тип int**. Стало быть под него надо выделить память
Итак, массив указателей создан и он где-то в памяти. Теперь надо под каждый из этих указателей выделить память, соответствующую второй размерность. Это мы делать умеем.
Теперь мы можем создавать двумерные динамические массивы. В заключении хотелось бы отметить, что таким образом мы можем создавать динамические массивы, размерность которых больше двух. Допустим трехмерный массив можно представить как одномерный массив двумерных массивов, ну а с двумерныи массивами мы уже разобрались! Теперь всё!
Как должно быть уже известно, имя масива фактически является указателем на первый элемент.
Т.е. если имеем
int *ptrArr; int Arr[10];то можем записать следующее
ptrArr = &Arr[0];или вот так
ptrArr = Arr;теперь ptrArr содержит адрес первого элемента массива Arr
И если теперь записать
int x =*ptrArr
то в x запишется значение первого элемента массива
К элементу массива мы можем обращаться как с помощью индекса Arr[i],так и с помощью указателя *(Arr+i), либо в нашем случае еще и *(ptrArr+i). Выражение Arr[i] автоматически преобразуется к *(Arr+i).
После такого вступления мы уже можем создать динамический массив. Для этого будем использовать функцию выделения памяти calloc(), которая имеет следующий прототип
void *calloc (size_t num, size_t size)
Функция выделяеи num*size байтов и возвращает указатель на первый элемент выделенной области либо null, если выделит память невозможно. Для использования необходимо подключить заголовок
#include <cstdlib>
Создадим динамический массив на 10 элементов:
int *p; p = (int*)calloc(10,sizeof(int)); // Выделяем память //... // какой-либо код free (p); // удалим массив, если он нам больше не нужен
Как видно из примеры, мы взяли указатель и выделили под него память на 10 int-значений. Вот так просто создаются одномерные массивы.
Теперь перейдем к двумерным. Пусть нам требуется создать массив 3*4 (3 строки, 4 столбца).
Двумерный массив мы можем представить как "массив одномерных массивов", т.е. как одномерный массив, элементами которого являеются так же одномерные массивы. Далее, следует, если у нас будет несколько массивов (элементов), стало быть для каждого из них должен быть свой указатель, а это уже получается, что мы должны иметь массив указателей. Этот массив указателей очевидно одномерный и надо его создать, а создавать одномерные динамические массивы мы уже умеем. Но тут есть дно "но"!
В предыдущем примере мы заводили массив int-элементов и указатель int* на первый элемент, а здесь у нас элементами являются указатели на int - int*, и тогда указатель на первый элемент у нас будет уже указателем на ... указатель! т.е. будет иметь тип int**. Стало быть под него надо выделить память
int **m; // указатель на указатель на int m = (int**)calloc(3,sizeof(int*));
Итак, массив указателей создан и он где-то в памяти. Теперь надо под каждый из этих указателей выделить память, соответствующую второй размерность. Это мы делать умеем.
for (int i=0; i<3; i++) *(m+i) = (int*)calloc(4,sizeof(int));Обратите внимание на запись *(m+i). Как говорилось выше, мы используем доступ к элементу массива с помощью указателя. Получив доступ к этому элементу массива указателей, мы можем выделить память и после этого перейти к следующему элементу. Можно бы было написать и так
m[i] = (int*)calloc(4,sizeof(int));Для удаления массива нужно проделать обратные действия: удалить массив под каждый указатель
for (int i=0; i<3; i++) free(*(m+i)); затем нужно удалить сам массив указателей free(m);
Теперь мы можем создавать двумерные динамические массивы. В заключении хотелось бы отметить, что таким образом мы можем создавать динамические массивы, размерность которых больше двух. Допустим трехмерный массив можно представить как одномерный массив двумерных массивов, ну а с двумерныи массивами мы уже разобрались! Теперь всё!
2 комментария :
вероятно в коде
И если теперь записать
x = &ptr
то в x запишется значение первого элемента массива
Имелось в виду
x = *ptrArr
Спасибо, поправил.
Отправить комментарий