Освоение указателей и многомерных массивов в C
В языке C массив — это совокупность значений одного типа, хранящихся в непрерывных ячейках памяти. Каждый элемент массива (одномерного или многомерного) идентифицируется одним или несколькими уникальными целочисленными индексами.
С другой стороны, указатель хранит адрес переменной. Адрес 0-го элемента массива является указателем массива. Вы можете использовать «оператор разыменования» для доступа к значению, на которое ссылается указатель.
Вы можете объявить одномерный, двумерный или многомерный массив в C. Термин «размерность» относится к количеству индексов, необходимых для идентификации элемента в коллекции.
Указатели и одномерные массивы
В одномерном массиве каждый элемент идентифицируется одним целым числом:
int a[5] = {1, 2, 3, 4, 5};
Здесь число «1» находится в нулевом индексе, «2» в индексе 1 и т. д.
Переменная, хранящая адрес 0-го элемента, является его указателем –
int *x = &a[0];
Проще говоря, имя массива тоже указывает на адрес 0-го элемента. Итак, вы также можете использовать это выражение –
int *x = a;
Пример
Поскольку значение указателя увеличивается на размер типа данных, «x++» перемещает указатель на следующий элемент массива.
#include <stdio.h>
int main(){
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int *ptr = arr;
while (i < length){
printf("arr[%d]: %d \n", i, *(ptr + i));
i++;
}
return 0;
}
Вывод
Когда вы запустите этот код, он выдаст следующий результат –
arr[0]: 1 arr[1]: 2 arr[2]: 3 arr[3]: 4 arr[4]: 5
Указатели и двумерные массивы
Если одномерный массив похож на список элементов, то двумерный массив похож на таблицу или матрицу.
Можно считать, что элементы двумерного массива логически расположены в строках и столбцах. Следовательно, местоположение любого элемента определяется двумя индексами:номером строки и номером столбца. Индексы строк и столбцов начинаются с «0».
int arr[2][2];
Такой массив представлен как —
Можно отметить, что табличное расположение является лишь логическим представлением. Компилятор выделяет блок непрерывных байтов. В C выделение массива осуществляется построчно, что означает, что элементы считываются в массив построчно.
Здесь мы объявляем двумерный массив с тремя строками и четырьмя столбцами (число в первой квадратной скобке всегда относится к количеству строк) как —
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
Компилятор выделит память для вышеуказанного двумерного массива построчно. Предполагая, что первый элемент массива находится по адресу 1000, а размер типа «int» составляет 4 байта, элементы массива получат следующие выделенные ячейки памяти —
Мы присвоим адрес первого элемента массива num указателю ptr, используя адрес оператора &.
int *ptr = &arr[0][0];
Пример 1
Если указатель увеличивается на 1, он перемещается к следующему адресу. Доступ ко всем 12 элементам массива «34» можно получить в цикле следующим образом:
#include <stdio.h>
int main(){
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
};
// pointer ptr pointing at array num
int *ptr = &arr[0][0];
int i, j, k = 0;
// print the elements of the array num via pointer ptr
for (i = 0; i < 3; i++){
for (j = 0; j < 4; j++){
printf("%d ", *(ptr + k));
k++;
}
printf("\n");
}
return 0;
}
Вывод
Когда вы запустите этот код, он выдаст следующий результат –
1 2 3 4 5 6 7 8 9 10 11 12
В общем случае адрес любого элемента массива можно получить по следующей формуле —
add of element at ith row and jth col = baseAddress + [(i * no_of_cols + j) * sizeof(array_type)]
В нашем массиве 34
add of arr[2][4] = 1000 + (2*4 + 2)*4 = 1044
Вы можете обратиться к приведенному выше рисунку, который подтверждает, что адрес «arr[3][4]» равен 1044.
Пример 2
Используйте указатель разыменования, чтобы получить значение по адресу. Давайте используем эту формулу для обхода массива с помощью его указателя —
#include <stdio.h>
int main(){
// 2d array
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int ROWS = 3, COLS = 4;
int i, j;
// pointer
int *ptr = &arr[0][0];
// print the element of the array via pointer ptr
for (i = 0; i < ROWS; i++){
for (j = 0; j < COLS; j++) {
printf("%4d ",*(ptr + (i * COLS + j)));
}
printf("\n");
}
return 0;
}
Вывод
Когда вы запустите этот код, он выдаст следующий результат –
1 2 3 4 5 6 7 8 9 10 11 12
Указатели и трехмерные массивы
Трехмерный массив — это массив двумерных массивов. Такой массив объявляется с тремя индексами —
int arr [x] [y] [j];
Этот массив можно рассматривать как количество слоев таблиц «x», каждая таблица имеет строк «x» и количество столбцов «y».
Пример 3D-массива:–
int arr[3][3][3] ={
{ {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
{ {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
{ {31, 32, 33}, {34, 35, 36}, {37, 38, 39} },
};
Указатель на 3D-массив можно объявить как —
int * ptr = &arr[0][0][0];
Зная, что имя самого массива является адресом 0-го элемента, мы можем записать указатель трехмерного массива как —
int * ptr = arr;
Каждый слой строк «x» и столбцов «y» занимает —
x * y * sizeof(data_type)
Количество байтов. Предполагая, что память, выделенная для 3D-массива "arr", как указано выше, начинается с адреса 1000, второй уровень (с "i =1") начинается с позиции 1000 + (3 3) 4 =1036 байт.
ptr = Base address of 3D array arr
Если JMAX — это количество строк, а KMAX — количество столбцов, то адрес элемента в 0-й строке и 0-м столбце 1-го среза равен —
arr[1][0][0] = ptr + (1 * JMAX * KMAX)
Формула для получения значения элемента в j-й строке и k-м столбце i-го среза может быть представлена как —
arr[i][j][k] = *(ptr + (i * JMAX*KMAX) + (j*KMAX + k))
Пример:печать 3D-массива с использованием разыменования указателя
Давайте воспользуемся этой формулой для печати 3D-массива с помощью разыменования указателя —
#include <stdio.h>
int main(){
int i, j, k;
int arr[3][3][3] = {
{ {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
{ {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
{ {31, 32, 33}, {34, 35, 36}, {37, 38, 39} },
};
int JMAX = 3, KMAX = 3;
int *ptr = arr; // &arr[0][0][0];
for(i = 0; i < 3; i++){
for(j = 0; j < 3; j++){
for(k = 0; k < 3; k++){
printf("%d ",*(ptr+(i*JMAX*KMAX)+(j*KMAX+k)));
}
printf("\n");
}
printf("\n");
}
return 0;
}
Вывод
Когда вы запустите этот код, он выдаст следующий результат –
11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27 28 29 31 32 33 34 35 36 37 38 39
В целом доступ к массиву с помощью указателя очень похож на доступ к массиву с индексным представлением. Основное различие между ними заключается в том, что индексное объявление массива выделяет память статически, тогда как мы можем использовать указатели для динамического выделения памяти.
Чтобы передать многомерный массив в функцию, вам нужно использовать указатели вместо индексов. Однако использовать массив с индексами удобнее, чем указатели, что может быть сложно для новичков.
Язык C
- Наследование С#
- C Обработка файлов
- Вложенный класс С#
- C# — перечисления
- Руководство по операторам C# IF, Switch, For, While [Примеры]
- Циклы в C:операторы циклов For, While, Do While [Примеры]
- Передача массива в функцию в программировании на C++
- Модификаторы доступа (спецификаторы) в C# с примерами программ
- C - определение типа
- Учебное пособие по Powershell для начинающих:изучите сценарии Powershell