Многомерный массив в C ++, для меня загадка :( - PullRequest
5 голосов
/ 30 января 2011

У меня много проблем с пониманием многомерных массивов.Пусть массив будет

x[2]; // now x is constant pointer to first element i.e x's name is address of x[0]

Теперь двумерный массив:

x[2][5]; // here x is address of x[0] which contains the address of first element of array x[][0];

Теперь указатель

int(*y)[5]; 

является указателем на массив 5 целых чисел.Как можно написать y = x?

Теперь я делал некоторые практические шаги, чтобы понять это в VS, который здесь, и мой главный вопрос в изображении:

http://img184.imagevenue.com/img.php?image=96382_first_122_1120lo.jpg

Пожалуйста, ответьте на вопрос концептуально;как C ++ хранит многомерный массив и т. д.

Буду очень признателен за любую помощь:)

Ответы [ 3 ]

7 голосов
/ 30 января 2011

Как уже указывали другие, многомерный массив - это массив массивов, а не массив указателей.

Я думаю, что основная причина недопонимания заключается в том, что любой массив на самом деле является указателем. Но это не совсем так. Массив - это переменная, в которой хранится непрерывная коллекция фиксированного размера элементов одного типа. Поэтому, когда вы объявляете массив типа int x[2], вы объявляете переменную, которая содержит два целых числа. Обратите внимание, что на нем нет указателя.

Теперь корень этого распространенного недоразумения состоит в том, что в C / C ++ имя массива оценивает по адресу его первого элемента и, следовательно, может использоваться как указатель. Другими словами, когда вы пишете x, вы подразумеваете &x или &x[0]. Вероятно, это было сделано для того, чтобы сделать выражения более читабельными.

Многомерный массив - это просто массив массивов. Другими словами, к ним относится та же логика, ничего особенного. Вы читаете объявление C / C ++, начиная с имени и выходя за пределы, применяя модификаторы по мере их появления, сначала [] и (), затем *, затем набираете, так что вы интерпретируете многомерный массив как этот (порядок чтения указан явно ):

int              x      [                2]         [           5];
6. "of type int" 1. "x" 2. "is an array" 3. "of 2". 4. "arrays" 5. "of 5 elements"

Таким образом, в C / C ++ нет такой вещи, как многомерные массивы, но есть такая вещь, как одномерный массив одномерных массивов. Согласно правилам для одномерных массивов, x, &x и &x[0] все оценивают по адресу первого элемента. Но поскольку первый элемент является массивом, x[0] вычисляет адрес этого массива, то есть адрес его первого элемента, который является целым числом. То же самое касается &x[0] и &x[0][0]. Вот почему значение x[0] совпадает с его адресом, поскольку x[0] является массивом.

Обратите внимание, что хотя эти объекты оцениваются по одному и тому же адресу, они имеют разные типы. x - это указатель на массив из 5-ти целых чисел, а также &x[0], так как оба они оценивают адрес первого элемента x. x[0] соответствует адресу первого элемента x[0], так что это указатель на int, то же самое относится и к &x[0][0]. Этот пример хорошо компилируется и печатает один и тот же адрес для всех 4 указателей:

  int x[2][5];
  int (*y1)[5] = x;
  int *y2 = x[0];
  int (*y3)[5] = &x[0];
  int *y4 = &x[0][0];
  printf("%p %p %p %p\n", y1, y2, y3, y4);

Теперь существуют разные макеты памяти для массивов, используемых на разных языках. Например, для двумерного массива вы можете сгруппировать элементы по строкам или столбцам. В C / C ++, поскольку нет «истинных» многомерных массивов, макет памяти неявно определяется приведенными выше правилами. Поскольку int x[2][5], который можно рассматривать как двумерный массив, имеющий 2 строки и 5 столбцов, на самом деле является массивом из 2 массивов, каждый из которых представляет строку, вы получаете макет «сгруппировать по строкам», который представлены в ответе Шибовича.

Обратите внимание, что также возможно создать массив указателей и использовать его в качестве многомерного массива. Отличия от «обычных» многомерных массивов:

  1. Массив указателей фактически содержит указатели внутри. То есть адреса первых элементов подмассивов.
  2. Структура памяти не является смежной. Каждый вложенный массив может быть размещен где угодно, например, с помощью malloc () или new [].
  3. Подмассивы могут быть разных размеров.

Преимущество этого подхода состоит в том, что вы можете использовать этот массив в качестве указателя на указатель (например, int **y), что делает все многомерные массивы такого типа совместимыми друг с другом, даже если они имеют разные размеры , Но размеры должны храниться отдельно в этом случае.

6 голосов
/ 30 января 2011

Посмотрите: любой многомерный массив - это массив массивов.Например, x[2][5] будет равно этой таблице:

x[0][0] x[0][1] x[0][2] x[0][3] x[0][4]

x[1][0] x[1][1] x[1][2] x[1][3]x[1][4]

Назначение указателя будет точно таким же: x[0] - первая строка в вашей таблице 2x5, поэтому int *y = x[0] или int *y = x[1] скопирует адрес изпервая строка в y.

Но если вы сделаете int (*y) = x, то она сохранит адрес x[0][0] в переменной y (int y создает экземпляр int, а int (*y) дает вам адресэтого экземпляра).

UPD: Пусть у нас будет int **x переменная.Неважно, какой у него размер.Просто примите это как истину, что x, x[0] и x[0][0] предоставят вам один и тот же адрес.Это можно объяснить как Pointer name means its address. Multi-dimensional array is a pointer to pointer. Its name means address of pointer it's pointing on which means address of the last pointer' first element. (извините за соучастие).

3 голосов
/ 30 января 2011

Поскольку имя одномерного массива считается указателем на первый элемент, конструкция x [0] является указателем на первый массив вашего двумерного массива, а x [1]это указатель на ваш второй массив.Итак, просто представьте x [0] как имя вашего первого массива.Добавление другой пары скобок (например, x [0] [0]) вернет вам значение элемента.И адрес первого элемента будет & x [0] [0] или просто x [0].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...