Мне нужно объяснение для следующего кода:
int a[2][3][2] = { 1,2,3,
4,5,6,
7,8,9,
10,11,12 };
std::cout << a[0][5][0];
Что касается multi dimensional arrays
, первый индекс указывает количество строк, второй индекс указывает количество столбцов, а третий индекс указывает количество массивов. Но здесь этот код дает мне 11
в качестве выхода, более того, что более шокирует
for(int i=0; i<12; i++)
std::cout<<a[0][0][i];
печатает все элементы массива. Я не мог найти объяснения такого доступа в любом месте в Интернете. Кто-нибудь, пожалуйста, уточните меня!
Мораль этой истории... "Нет ложки" (Матрица).
Нет строк, столбцов и страниц. просто память с линейной последовательностью, где элементы хранятся только один за другим.
Многомерные массивы - это просто "проекция", а идея или страницы/строки/столбцы - это просто абстракция.
a[k][j][i]
просто означает (уровни направленности отдельно) *(a + k*Y*X + j*X + i)
где Z, X и Y - размеры размеров. Скорее всего, мы называем "страницы", "строки" и "столбцы".
Обратите внимание, что. независимо от Z, Y и X, полагая k = 0, j = 0, я = 11, в эквивалентном выражении имеет смысл и будет ссылаться на значение 12.
Ожидаемые результаты будут выполняться только в том случае, если вы находитесь в пределах a[2][3][2]
. То есть, когда вы делаете a[0][0][0]
до a[1][2][1]
, ваши предположения будут выполняться. Но как только вы пересечете эту границу, результаты, которые вы видите, уже не совпадают.
Здесь на самом деле происходит то, что a[i][j][k]
технически совпадает с элементами k+j*2+i*2*3
после первого, учитывая номера, которые вы использовали в своем коде. Это позволяет иметь представление вашего массива, который выглядит "3D", но на самом деле в памяти они "находятся в строке" или в одномерном массиве. Таким образом, делая это *2
и *2*3
вы фактически переходите к "следующему" подматрицу.
Почему он не работает, когда вы выходите из пределов a[2][3][2]
? Возьмем, к примеру, для a[i][j][k]
с k=4
, он будет эквивалентен i*2*3 + j*2 + k = i*2 + (j+1)*3 + 1
. Так что он как будто "подпрыгнул" до следующей строки/столбца/что угодно.
Вы можете визуализировать это лучше на двумерном массиве, представив таблицу и пройдя через строку, и как только вы выйдете за последний столбец строки, вы попадете в строку под ней.
Однако C не предупреждает вас, когда вы выходите из границ вашего многомерного массива или когда вы "падаете" из строки, в которой вы находитесь.
Обновить
Вы правы, говоря, a[0][5][0]
не существует. Что происходит в этом случае, так это то, что вы действительно будете читать что-то еще, что находится в памяти, рядом с a
. Например, допустим, что у вас есть a
и b
в коде, когда вы имеете дело с a
и b
в коде, что происходит под капотом, так это то, что a
и b
- всего лишь часть памяти. И пусть say a
- это массив из 12 элементов в целом, когда вы выходите за пределы этих 12 элементов, C просто предположим, что массив такой же большой, как вы говорите, и загляните в кусок памяти, который после 15 "кусков" и даст вам это. Таким образом, a[15]
но он не принадлежит массиву. Он может принадлежать b
если они находятся рядом друг с другом в памяти или может принадлежать чему-то другому целиком.
Техническая терминология является то, что при объявлении как массив размера 12 целых чисел, он будет выделять память 12 целых чисел (12 * 4 байта) рядом друг с другом и обозначьте, что в качестве для вас. a
a
a
укажет на начало этой части памяти; это указатель. Когда вы сделаете a[x]
или a[i][j][k]
вы получите указатель на x-й кусок памяти a. И если x больше 12, он выйдет за пределы и захватит все, что там лежит, и подумайте, что это целое число. (в то время как это может быть что-то другое, поэтому вы можете получить мусор, когда делаете это, потому что на самом деле это может быть что-то другое, и они интерпретируют его так, как если бы оно было целым числом).
Подумайте об этом так.
a [2] [3] [2] на самом деле является просто [12], сгруппированным в группы из 2, тогда 3.
a [0] [5] [0] действительно является [0] [0] [5 * 2] = a [0] [0] [10]
Это связано с тем, что массив загружается в непрерывную память.
Многомерные массивы хранятся в памяти в памяти постоянной памяти, поэтому ваш массив выглядит в памяти следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12
Поскольку C не поддерживает проверку привязки к массиву, вы можете получить доступ к памяти после предела массива, даже нераспределенной памяти (это иногда приводит к ошибкам).
Доступ a [x] [y] [z] вычисляется с использованием значений x, y, z и размера массива a в адресе памяти относительно a (как вы знаете, a является указателем на первый элемент в массиве, [0] [0] [0], в этом случае).
int a[2][3][2]
лиint a[2][3][2]
отint a[12]
?