В языке C массивы предназначены для хранения данных сходного типа в смежных ячейках памяти. Мы можем создавать массивы либо из примитивных типов данных, таких как int, char или float, либо из пользовательских типов данных, таких как структуры и объединения. Мы также можем создавать массивы указателей на языке C. Сегодня мы узнаем, как создавать массивы указателей структуры или указателей на структуру на языке C, как статически, так и динамически.
Создание массивов указателей структуры (статические массивы)
1) 1D Arrays
Мы можем статически выделить память для 1D и 2D массивов на языке C. Статическая память выделяется в памяти стека. Мы можем сделать статическое выделение памяти для указателей структур следующими способами:
Шаг 1 — Объявление и инициализация одномерных массивов
Допустим, у нас есть структура «узел», и мы создали разные указатели на эту структуру. Теперь, чтобы создать одномерный массив этих указателей в статической памяти, мы должны следовать следующему синтаксису:
Синтаксис:
<struct_name> * <array_name> [ <size_of_array> ] ; // Declaration <array_name> [ <index_number> ] = <pointer_to_the_structure> ; // Initialization
Мы можем получить доступ к указателям внутри нашего массива так же, как мы обращаемся к обычным элементам массива. Есть только небольшая модификация, которую нам нужно использовать для доступа к данным, присутствующим внутри нашего указателя структуры.
Шаг 2 — Доступ к указателям в массиве
Синтаксис:
<array_name> [<index_number>] -> <data to be accessed which is present inside the structure >
Пример:
С
// C Program to implement
// structure pointer arrays
#include <stdio.h>
#include <stdlib.h>
typedef
struct
node {
int
number;
char
character;
} node;
int
main(
void
)
{
// First pointer to structure
node* structure_ptr1 = (node*)
malloc
(
sizeof
(node));
// Second pointer to structure
node* structure_ptr2 = (node*)
malloc
(
sizeof
(node));
// Declaration of
// structure-pointer-array of size 2
node* struct_array[2];
// Initializing structure pointers
structure_ptr1->number = 100;
structure_ptr1->character =
'a'
;
structure_ptr2->number = 200;
structure_ptr2->character =
'b'
;
// Initializing this array with pointers
struct_array[0] = structure_ptr1;
struct_array[1] = structure_ptr2;
// Printing data of structures
printf
(
"Data:\n"
);
printf
(
"%d and %c\n"
, struct_array[0]->number,
struct_array[0]->character);
printf
(
"%d and %c\n"
, struct_array[1]->number,
struct_array[1]->character);
return
0;
}
Выход
Data: 100 and a 200 and b
В приведенном выше примере у нас есть структура, называемая «узел». Мы сделали 2 указателя на эту структуру, а именно — «structure_ptr1» и «structure_ptr2» и инициализировали их. После этого мы объявили массив — «struct_array» размера 2 и инициализировали его нашими указателями на структуру.
2) 2D-массивы
Шаг 1 — Объявление и инициализация 2D-массивов
Синтаксис:
<structure_name> * <array_name> [number_of_rows][number_of_columns]; <array_name> [row_number][column_number] = <pointer_to_structure> ;
Шаг 2. Доступ к элементам нашего 2D-массива
Синтаксис:
< array_name >[ <row_number> ][ <column_number> ] -> <data to be accessed which is present inside the structure >;
Пример:
С
// C Program to implement
// structure pointer 2-D array
#include <stdio.h>
#include <stdlib.h>
typedef
struct
node {
int
number;
char
character;
} node;
int
main(
void
)
{
// First pointer to structure
node* structure_ptr1 = (node*)
malloc
(
sizeof
(node));
// Second pointer to structure
node* structure_ptr2 = (node*)
malloc
(
sizeof
(node));
// Third pointer to structure
node* structure_ptr3 = (node*)
malloc
(
sizeof
(node));
// Fourth pointer to structure
node* structure_ptr4 = (node*)
malloc
(
sizeof
(node));
// Declaration of
// structure-pointer-array
// of size 2 X 2
node* structure_array[2][2];
// Initializing structure pointers
structure_ptr1->number = 100;
structure_ptr1->character =
'a'
;
structure_ptr2->number = 200;
structure_ptr2->character =
'b'
;
structure_ptr3->number = 300;
structure_ptr3->character =
'c'
;
structure_ptr4->number = 400;
structure_ptr4->character =
'd'
;
// Initializing this array with pointers
structure_array[0][0] = structure_ptr1;
structure_array[0][1] = structure_ptr2;
structure_array[1][0] = structure_ptr3;
structure_array[1][1] = structure_ptr4;
// Accessing the values of these structure pointers from
// 2D array
printf
(
"Data:\n"
);
for
(
int
i = 0; i < 2; i++) {
for
(
int
j = 0; j < 2; j++) {
printf
(
"%c - "
,
structure_array[i][j]->character);
printf
(
"%d\t\t"
, structure_array[i][j]->number);
}
printf
(
"\n"
);
}
}
Выход
Data: a - 100 b - 200 c - 300 d - 400
Вот как мы объявляем и инициализируем двумерный массив указателей на структуры. Здесь мы используем ту же структуру — «узел» и сделали для нее 4 указателя: «structure_ptr1», «structure_ptr2», «structure_ptr3» и «structure_ptr4». После этого мы объявили 2D-массив размером — 2 X 2, а именно —structure_array.
Примечание. Тип данных массива должен быть таким же, как и у структуры, за которой следует знак * (звездочка), что означает массив указателей структуры.
Создание массивов указателей структур (динамические массивы)
1) 1D массивы
Поскольку мы знаем, что в языке C мы также можем динамически выделять память для наших переменных или массивов. Динамически выделяемые переменные или массивы хранятся в куче. Чтобы динамически выделять память для массивов указателей структур, необходимо следовать следующему синтаксису:
Синтаксис:
< structure_name > ** < array_name > = <structure_name **> malloc ( sizeof( <structure_name> )* size ) ;
Обратите внимание на двойной указатель после имени структуры и во время приведения типа malloc к структуре. Этот двойной указатель необходим, поскольку мы указываем на массив указателей на структуру, и мы знаем, что используем двойные указатели, если хотим указать на другой указатель.
Пример:
С
// C Program to implement
// Dynamic Array of structure
// pointer
#include <stdio.h>
#include <stdlib.h>
typedef
struct
node {
int
number;
char
character;
} node;
int
main(
void
)
{
// First pointer to structure
node* structure_ptr1 = (node*)
malloc
(
sizeof
(node));
// Second pointer to structure
node* structure_ptr2 = (node*)
malloc
(
sizeof
(node));
// Third pointer to structure
node* structure_ptr3 = (node*)
malloc
(
sizeof
(node));
// Fourth pointer to structure
node* structure_ptr4 = (node*)
malloc
(
sizeof
(node));
// Initializing structure pointers
structure_ptr1->number = 100;
structure_ptr1->character =
'a'
;
structure_ptr2->number = 200;
structure_ptr2->character =
'b'
;
structure_ptr3->number = 300;
structure_ptr3->character =
'c'
;
structure_ptr4->number = 400;
structure_ptr4->character =
'd'
;
// Declaring the array dynamically for structure
// pointers
// Note that double pointer is
// used for pointer to pointer
node** structure_array
= (node**)
malloc
(
sizeof
(node) * 4);
// Initializing the array of structure pointers
structure_array[0] = structure_ptr1;
structure_array[1] = structure_ptr2;
structure_array[2] = structure_ptr3;
structure_array[3] = structure_ptr4;
// Accessing dynamic 1D arrays - just like static 1D
// arrays
printf
(
"Data:\n"
);
for
(
int
i = 0; i < 4; i++) {
printf
(
"%c - "
, structure_array[i]->character);
printf
(
"%d\t\t"
, structure_array[i]->number);
printf
(
"\n"
);
}
}
Выход
Data: a - 100 b - 200 c - 300 d - 400
Вы можете ясно видеть в приведенном выше коде, как мы инициализировали массив указателей структуры в конце. Разница между этим и статическими массивами заключается только в том, что статические массивы размещаются в памяти стека, а они — в памяти кучи. Итак, вы можете изменить размер этих массивов в любое время.
Мы можем получить доступ к этим массивам точно так же, как и к статическим, поэтому для этого нет никаких изменений в синтаксисе.
Примечание. В случае статических массивов вы можете инициализировать весь массив сразу во время инициализации, например — node *struct_arr [10] = { struct_ptr1, struct_ptr2, struct_ptr3 …..}, тогда как динамически размещаемые массивы необходимо инициализировать индексом -по индексу.
2) 2D-массивы
Чтобы выделить динамические 2D-массивы указателей, сначала мы создадим 1D-массив динамически, а затем создадим подмассивы в каждом индексе этого 1D-массива (в основном массив массивов, содержащих указатели). Теперь для этого требуется использование тройных указателей. Разберемся в этом с помощью схемы:
Пояснение к приведенному выше рисунку:
- *** st_arr — это тройной указатель, используемый для доступа к двумерному массиву указателей структур. Теперь он сделан тройным указателем, потому что мы обращаемся к тем
- массивам, каждый элемент которых имеет указатель на другой массив (подмассив). И каждый элемент этих подмассивов имеет указатель на структуру.
- Каждый индекс st_arr[i] содержит подмассивы.
- Каждый индекс подмассивов — st_arr[i][j] содержит указатель на структуру.
- st_ptr — указатель на структуру.
Пример:
С
// C Program to implement
// 2D arrays of structure
#include <stdio.h>
#include <stdlib.h>
typedef
struct
node {
int
number;
char
character;
} node;
int
main(
void
)
{
// First pointer to structure
node* st_ptr1 = (node*)
malloc
(
sizeof
(node));
// Second pointer to structure
node* st_ptr2 = (node*)
malloc
(
sizeof
(node));
// Third pointer to structure
node* st_ptr3 = (node*)
malloc
(
sizeof
(node));
// Fourth pointer to structure
node* st_ptr4 = (node*)
malloc
(
sizeof
(node));
// Initializing structure pointers
st_ptr1->number = 100;
st_ptr1->character =
'a'
;
st_ptr2->number = 200;
st_ptr2->character =
'b'
;
st_ptr3->number = 300;
st_ptr3->character =
'c'
;
st_ptr4->number = 400;
st_ptr4->character =
'd'
;
// Declaring the array dynamically for structure
// pointers Step - 1
// Note that double pointer is
// used for pointer to pointer
node*** structure_array
= (node***)
malloc
(
sizeof
(node***) * 2);
// Used double pointers, at each index to point to
// arrays of structure pointers - Step 2
for
(
int
i = 0; i < 2; i++) {
structure_array[i] = (node**)
malloc
(
sizeof
(node**));
}
// Initializing the array of structure pointers - Step
// 3
structure_array[0][0] = st_ptr1;
structure_array[0][1] = st_ptr2;
structure_array[1][0] = st_ptr3;
structure_array[1][1] = st_ptr4;
// Printing the values of these structure pointers from
// array
printf
(
"Data:\n"
);
for
(
int
i = 0; i < 2; i++) {
for
(
int
j = 0; j < 2; j++) {
printf
(
"%c - "
,
structure_array[i][j]->character);
printf
(
"%d\t\t"
, structure_array[i][j]->number);
}
printf
(
"\n"
);
}
}
Выход
a - 100 b - 200 c - 300 d - 400
- В приведенном выше коде, как мы уже обсуждали, тройной указатель использовался для указания на массив массивов, содержащих указатели на структуры.
- На втором этапе мы использовали двойные указатели, так как нам нужно было использовать указатель, который мог указывать на массив указателей на структуры.
- На третьем шаге мы инициализировали наш динамический 2D-массив, как и статический 2D-массив, индексируя по -index.