доступ к многомерному массиву в c

0

Мне нужно объяснение для следующего кода:

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];

печатает все элементы массива. Я не мог найти объяснения такого доступа в любом месте в Интернете. Кто-нибудь, пожалуйста, уточните меня!

  • 0
    Массивы выложены в непрерывной памяти. Я думаю, что это технически неопределенное поведение, но на него сильно полагается делать что-то кроме этого.
  • 0
    Подумайте о расположении памяти многомерного массива. int a[2][3][2] ли int a[2][3][2] от int a[12] ?
Теги:
arrays
multidimensional-array

4 ответа

1
Лучший ответ

Мораль этой истории... "Нет ложки" (Матрица).

Нет строк, столбцов и страниц. просто память с линейной последовательностью, где элементы хранятся только один за другим.

Многомерные массивы - это просто "проекция", а идея или страницы/строки/столбцы - это просто абстракция.

a[k][j][i] просто означает (уровни направленности отдельно) *(a + k*Y*X + j*X + i)

где Z, X и Y - размеры размеров. Скорее всего, мы называем "страницы", "строки" и "столбцы".

Обратите внимание, что. независимо от Z, Y и X, полагая k = 0, j = 0, я = 11, в эквивалентном выражении имеет смысл и будет ссылаться на значение 12.

1

Ожидаемые результаты будут выполняться только в том случае, если вы находитесь в пределах 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, он выйдет за пределы и захватит все, что там лежит, и подумайте, что это целое число. (в то время как это может быть что-то другое, поэтому вы можете получить мусор, когда делаете это, потому что на самом деле это может быть что-то другое, и они интерпретируют его так, как если бы оно было целым числом).

  • 0
    Могу ли я узнать, откуда вы взяли эти знания? Я не нашел эту информацию ни в Интернете, ни в какой-либо книге. У меня есть несколько вопросов без ответов, я просто хочу иметь некоторую базу знаний в руках.
  • 0
    согласно вашему объяснению a [0] [5] [0] должно стать (0 + 5 * 3 + 0 * 2 * 3), что равно [15], который не существует.
Показать ещё 3 комментария
1

Подумайте об этом так.

a [2] [3] [2] на самом деле является просто [12], сгруппированным в группы из 2, тогда 3.

a [0] [5] [0] действительно является [0] [0] [5 * 2] = a [0] [0] [10]

Это связано с тем, что массив загружается в непрерывную память.

  • 0
    a [0] [0] [5 * 2]! = a [10], поскольку a [10] распадается в двумерный массив
  • 0
    Спасибо, что поймали это. Немного впереди себя
Показать ещё 2 комментария
0

Многомерные массивы хранятся в памяти в памяти постоянной памяти, поэтому ваш массив выглядит в памяти следующим образом:

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], в этом случае).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню