Многомерные статические массивы
В си, наряду с одномерными, существуют и многомерные массивы. Например, двумерный массив: его можно представлять как массив массивов, или как матрицу. Размерность массива может быть и больше: трёхмерные, четырёхмерные и т.д.
Синтаксис остаётся прежним, добавляется только новая размерность
[размерность1][размерность2]. ;
Например, двумерный массив
int a[2][3];
int a[3][4][5];
Доступ до элементов массива осуществляется также, как и в одномерном массиве
#include #include #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] = ; int b[][5][25] = ;
Компилятор будет знать в таком случае сдвиг, необходимый для доступа к элементу.
С этим связаны и особенности начальной инициализации. Так как многомерный массив по сути одномерный, то его начальную инициализацию можно провести так
int a[2][3] = ;
Можно опустить первую размерность
int a[][2][3] = ;
Можно с помощью фигурных скобок сделать данные более удобными для чтения
int a[2][3] = {{1, 2, 3>,int a[][3][4] = {{{1, 2, 3, 4>, , , , , ,Также, как и в одномерных массивах, если заявлено данных больше, чем указано при инициализации, то оставшиеся заполняются нулями. Например, единичная матрица 3 на 3
int zero3[3][3] = {{1>, ,Из того, что многомерный массив является одномерным по структуре, вытекают некоторые интересные свойства. Например, доступ до элемента может быть осуществлён через его порядковый номер
a[i][j] === a[0][i*число столбцов + j] и т.д.Примеры
1. Отсортируем двумерный массив методом пузырька. Для сортировки обычно используется два подхода - превращение двумерного массива в одномерный, сортировка, обратно превращение одномерного в двумерный, либо запутанное обращение к элементам через индекс. Можно сделать всё проще: работать с многомерным массивом как с одномерным
#include #include #define ROWS 4 #define COLS 3 void main() < int a[ROWS][COLS] = {{1, 4, 5>, , , > > 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 #include #include #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>, 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 #include #include #define SIZE 5 #define START 2 #define FINISH 3 void main() < char field[SIZE][SIZE] = < , , , , >; 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 #include #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(); >ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students
Всё ещё не понятно? – пиши вопросы на ящик
Инициализировать многомерные массивы в C
В этом посте мы обсудим, как инициализировать многомерные массивы на языке программирования C.
Многомерный массив — это массив с более чем одним измерением. Простейшим многомерным массивом является двумерный массив или двумерный массив. Это в основном массив массивов, который также широко известен как матрица. Общий синтаксис инициализации массива применим и к многомерным массивам.
1. Использование статического хранилища
Все объекты в C со статической продолжительностью хранения устанавливаются равными 0, которые не были явно инициализированы программистом. Следующий код инициализирует первую ячейку 6 × 8 матрицу в 0, а остальные элементы как если бы они имели статическую продолжительность хранения, т.е. инициализировались нулем.
Инициализация двумерного динамического массива
@VTT а почему? Что происходит во вторым? Почему даже значение элемента второго элемента нельзя получить?
8 ноя 2019 в 20:25
Видимо вы рассчитывали на то, что new int[n] < 0 >будет вызываться для каждого элемента, однако все, кроме первого, будут инициализироваться нулями.
8 ноя 2019 в 20:26
@VTT массивами то они должны, по идее, остаться, даже если они инициализированы нулями. Или в двумерном массиве ссылки (ну или указатели) на одномерные хранятся?
8 ноя 2019 в 20:28
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
При инициализации массива с указанным размером отсутствующие инициализаторы - нули. Т.е.
int a[5] = ;
заполняет массив a значениями 6,0,0,0,0.
Заметим - инициализация значением, а не вычислением выражения 🙂
int i = 0; int a[5] = ;
не будет применять i++ ко всем элементам массива.
new int* [n] < new int[n] < 0 >>;
? Вычисляется единственное значение new int[n] < 0 >, присваивается первому элементу массива. Остальные заполняются нулями. Дальнейшее понятно? 🙂
Если вы хотите использовать именно C++, а не некий мутированный C, то vector вам в руки:
vector> ints(n, vector(n,0));
И никаких забот с освобождением памяти 🙂
Update
По дополненному вопросу - при полном отсутствии инициализатора как такового никакая инициализация не выполняется, и массив в результате заполнен мусором.
Инициализация массива
С позволяет инициализировать глобальные и локальные массивы на этапе объявления. Стандартный вид инициализации массива аналогичен инициализации переменных, как показано ниже:
спецификатор типа имя_массива [размерN] . [размер1] = ;
Список значений - это разделенный запятыми список констант, совместимых по типу со спецификатором типа. Первая константа помещается в первый элемент массива, вторая - во второй и так далее. За последней константой списка нет запятой. Обратим внимание, что точка с запятой следует за >. В следующем примере 10-элементный целочисленный массив инициализируется числами от 1 до 10:
Это означает, что i[0] получит значение 1, i[9] - 10.
Массивы символов, содержащие строки, допускают удобную инициализацию в виде
char имя_массива [размер] = "строка";
При данной инициализации нулевой терминатор автоматически добавляется к концу строки. Нижеприведенный фрагмент кода инициализирует строку str фразой «hello»:
char str[6] = "hello";
Это можно также записать:
Обратим внимание, что в данной версии следует явным образом указать нулевой символ. Поскольку все строки в С оканчиваются нулевым символом, следует убедиться, что массив достаточно длинный для его вмещения. Именно поэтому str состоит из 6 символов, хотя «hello» имеет только 5 символов.
Многомерные массивы инициализируются так же, как и одномерные. Следующий пример инициализирует sqrs числами от 1 до 10 и их квадратами:
Здесь sqrs[0][0] содержит 1, sqrs[0][1] содержит 1, sqrs[1][0] содержит 2, sqrs[1][1] содержит 4 и так далее.
При инициализации многомерных массивов можно добавить фигурные скобки вокруг каждого измерения. Это так называемая субагрегатная группировка. Ниже приведен еще один способ записи предыдущего объявления:
При использовании субагрегатной группировки в случае неуказания требуемого количества инициализаторов для данной группы остальные члены установятся в 0 автоматически.