Многомерные статические массивы
Многомерные статические массивы
В си, наряду с одномерными, существуют и многомерные массивы. Например, двумерный массив: его можно представлять как массив массивов,
или как матрицу. Размерность массива может быть и больше: трёхмерные, четырёхмерные и т.д.
Синтаксис остаётся прежним, добавляется только новая размерность
<тип> <имя>[размерность1][размерность2]...;
Например, двумерный массив
int a[2][3];
Трёхмерный массив
int a[3][4][5];
Доступ до элементов массива осуществляется также, как и в одномерном массиве
#include <conio.h> #include <stdio.h> #define SIZE 5 void main() { int M[3][3]; unsigned i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { M[i][j] = i * j; } } do { printf("enter indexes:\n"); scanf("%d", &i); scanf("%d", &j); if (i < 3 && j < 3) { printf("M[%d][%d] == %d\n", i, j, M[i][j]); } else { break; } } while (1); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { printf("\t%d", M[i][j]); } printf("\n"); } getch(); }
Особенностью является то, что по своему строению многомерный массив является обыкновенным, "одномерным", массивом. Все элементы расположены друг за другом. Доступ до элемента
a[i][j]
– по существу сдвиг на i*число столбцов + j. В двумерном массиве, таким образом, элементы расположены "по рядам", в трёхмерном - "по слоям",
внутри которых элементы расположены "по рядам" и т.д.
В связи с этим, при начальной инициализации опускать размерность можно только в первых квадратных скобках:
int a[][3] = {0}; int b[][5][25] = {0};
Компилятор будет знать в таком случае сдвиг, необходимый для доступа к элементу.
С этим связаны и особенности начальной инициализации. Так как многомерный массив по сути одномерный, то его начальную инициализацию можно провести так
int a[2][3] = {1, 2, 3, 4, 5, 6};
Можно опустить первую размерность
int a[][2][3] = {1, 2, 3, 34, 5, 6, 7, 8, 9, 10, 11, 12};
Можно с помощью фигурных скобок сделать данные более удобными для чтения
int a[2][3] = {{1, 2, 3}, {4, 5, 6}}
или
int a[][3][4] = {{{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}}, {{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}}, {{1, 2, 3, 4}, {2, 4, 6, 8}, {3, 6, 9, 12}}};
Также, как и в одномерных массивах, если заявлено данных больше, чем указано при инициализации, то оставшиеся заполняются нулями. Например, единичная матрица 3 на 3
int zero3[3][3] = {{1}, {0, 1}, {0, 0, 1}};
Из того, что многомерный массив является одномерным по структуре, вытекают некоторые интересные свойства. Например, доступ до элемента может быть осуществлён через его
порядковый номер
a[i][j] === a[0][i*число столбцов + j]
и т.д.
Примеры
1. Отсортируем двумерный массив методом пузырька. Для сортировки обычно используется два подхода - превращение двумерного массива в одномерный, сортировка, обратно превращение одномерного в двумерный, либо запутанное обращение к элементам через индекс. Можно сделать всё проще: работать с многомерным массивом как с одномерным
#include <conio.h> #include <stdio.h> #define ROWS 4 #define COLS 3 void main() { int a[ROWS][COLS] = {{1, 4, 5}, {2, 6, 8}, {1, 0, 9}, {4, 2, 8}}; int i, j, tmp, flag; do { flag = 0; for (i = 1; i < ROWS*COLS; i++) { if (a[0][i] < a[0][i-1]) { tmp = a[0][i]; a[0][i] = a[0][i-1]; a[0][i-1] = tmp; flag = 1; } } } while(flag); for (i = 0; i < ROWS; i++) { for (j = 0; j < COLS; j++) { printf("%3d", a[i][j]); } printf("\n"); } _getch(); }
Замечание: по стандарту явно такое поведение не определено, но косвенно должно поддерживаться.
2. Даны координаты x и y точки, полученные в ходе фотосъёмки. Известно, сколько кадров в секунду делала камера. Вычислить скорость в каждый момент времени и среднюю скорость за всё время.
#include <conio.h> #include <stdio.h> #include <math.h> #define SIZE 10 void main() { float a[2][SIZE] = {{1.03, 1.52, 2.11, 2.53, 3.08, 3.48, 3.98, 4.51, 5.02, 5.17}, {1.03, 2.45, 4.13, 5.64, 7.22, 8.73, 10.32, 11.75, 13.28, 14.87}}; float velocity[SIZE-1]; float speed = 0.0; float vx, vy; float dt = 0.1; int i; for (i = 0; i < SIZE-1; i++) { vx = ( a[0][i+1] - a[0][i] ) / dt; vy = ( a[1][i+1] - a[1][i] ) / dt; velocity[i] = sqrt(vx*vx + vy*vy); speed += velocity[i]; } speed /= (float)(SIZE - 1); for (i = 1; i < SIZE; i++) { printf("v[%d] = %.3f m/s\n", i, velocity[i-1]); } printf("mean velocity = %.3f", speed); _getch(); }
3. Массив используется как карта, где число 2 означает начало, а 3 - конец пути. Программа сначала находит координаты этих точек, после этого вычисляет расстояние Манхеттена (сколько нужно пройти по x и y от начала до конца) и расстояние по Евклиду (как гипотенузу прямоугольного треугольника).
#include <conio.h> #include <stdio.h> #include <math.h> #define SIZE 5 #define START 2 #define FINISH 3 void main() { char field[SIZE][SIZE] = { {0, 0, 0, 0, 0}, {2, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 3} }; unsigned i, j; unsigned x, y; char xFound = 0; int X, Y; char XFound = 0; unsigned manhattanDist; float euclidDist; for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { if (field[i][j] == START) { x = i; y = j; xFound = 1; if (XFound) { break; } } if (field[i][j] == FINISH) { X = i; Y = j; XFound = 1; if (xFound) { break; } } } if (xFound && XFound) { break; } } if (!(xFound && XFound)) { printf("Error: corrupted data\n"); getch(); exit(1); } printf("(x,y) = %d, %d\n(X,Y)= %d, %d\n", x, y, X, Y); manhattanDist = abs((int)(x-X)) + abs((int)(y-Y)); //тоже самое, что и sqrt((x-X)*(x-X)+(y-Y)*(y-Y)) x -= X; y -= Y; euclidDist = sqrt((float)(x*x + y*y)); printf("Manhattan dist. = %d\nEuclid dist. = %.3f", manhattanDist, euclidDist); getch(); }
4. Пользователь вводит 10 слов. Вывести слово с максимальной длиной. Программа внешне совершенно простая, единственная проблема - считывание и вывод слова. Так как слова храняться в двумерном массиве, то указатель на words[i][0] - это начало нового слова. Также не забываем об ограничении на длину при вводе.
#include <conio.h> #include <stdio.h> #define SIZE 10 #define MAX_LENGTH 128 void main() { //Массив хранит 10 слов максимум по 128 символов char words[SIZE][MAX_LENGTH]; unsigned i, j, maxLength; //Так как длина слова ограничена 127 символами, то типа char хватит unsigned char counter[SIZE]; for (i = 0; i < SIZE; i++) { //Считываем слова. words[i][0] - это символ, нам нужен //адрес, начиная с которого можно писать в массив fgets(&words[i][0], MAX_LENGTH - 1, stdin); j = 0; //Считаем длину слова while (words[i][j]) { j++; } counter[i] = j; } //Ищем слово с максимальной длиной maxLength = counter[0]; j = 0; for (i = 1; i < SIZE; i++) { if (counter[i] > maxLength) { maxLength = counter[i]; j = i; } } //Выводим слово на печать. При выводе строки //необходимо передавать указатель printf("%s", &words[j][0]); _getch(); }
