Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
1

Внутреннее устройство многомерного массива и неявное преобразование массива в указатель

20.12.2014, 12:15. Просмотров 1068. Ответов 22
Метки нет (Все метки)

Букв получилось многовато. Поэтому, чтобы сэкономить Ваше время, предлагаю сразу вопрос:
Буду очень благодарен, если кто-то сможет конкретизировать, как всё-таки устроен логически внутри себя многомерный массив в C++ и в какие моменты происходят в нём неявные преобразования?

Далее моя попытка разобраться в этом и нащупать логику (если времени на это нет, то считайте, что пост для Вас ограничен только текстом выше).

C++
1
2
3
int b [2][3] = {{11,22,33}, {55,66,77}};
/*#1*/ cout<< (*b)[1];   //out: 22
/*#2*/ cout<< *b[1];     //out: 55
Пытаюсь разобраться, где именно происходят неявные преобразования(разложение) в этих выражениях.
Предполагаю:
#1:
1.1) b - неявно преобразуется (далее -->) из объекта "2D-массив" - в ptr на первый его эл-т - т.е. в ptr на 1D-массив элементов типа int*
1.2) к результату 1.1 применяется разыменование `(*b)`. Т.е. ptr на 1D-массив int* --> в объект 1D-массив int*
1.3) неявно --> в ptr на свой 1й элемент - т.е. в ptr на 1D-субмассив элементов типа int
//Тут становится понятно, что логика эта какая-то кривая, т.к. 1.4 должен выполнять адресацию по ptr'у на массив. Если бы так, то на выходе мы получили бы скорее адрес 1го элемента второго массива из 3-х интов (т.е. адрес эл-та "55"). Но никак не значение "22".

Пробую другую логику:
Считаю, что объект массив существует только для самого внешнего объекта многомерного массива. Тогда получается:

#1:
1.1) b - неявно преобразуется (далее -->) из объекта "2D-массив" - в ptr на первый его эл-т - т.е. в ptr на int* (т.е. в int**)
1.2) к результату 1.1 применяется разыменование `(*b)`. Т.е. получаем int* (ptr на "11", т.е. на 1й эл-т первого субмассива)
1.3) процедура адресации `[1]` выполняет 2 функции: сдвиг и разыменование. Т.о. получаем значение "22".

Вроде получается пока красиво.
Но попытаюсь применить эту же логику к случаю #2

#2:
2.1) b - неявно --> из объекта "2D-массив" - в ptr на первый его эл-т - т.е. в ptr на int* (т.е. в int**)
2.2) процедура адресации `[1]` выполняет сдвиг и разыменование. ...
//Тут становится ясно, что эта логика не работает, т.к. мы в результате шага 2.2 получили бы следующее: int** сдвинулся бы на 1 соответственно указываемому типу - т.е. на 4 байта указателя, а разыменование (которое подразумевается вторым действием оператора адресации) дало бы ptr на "22". И тогда последнее действие собственно разыменования явно указанного дало бы окончательный результат тоже "22". Но не "55".

Т.е. должна быть, видимо, какая-то внутренняя таблица размеров указываемых объектов для указателей, получившихся в результате объявления массива на каждом уровне (разве что только кроме последнего). А, следовательно, тогда уж мы возвращаемся к тому, что должны быть объекты "массив" не только для внешнего уровня, но мы это как-будто бы опровергли выше.

Попробую найти компромиссную логику:
Что если действительно объект массив существует не для всех уровней многомерного массива. А, предположим, для всех, кроме последнего. И объект этот в нашем случае НЕ "Массив элементов типа int**", а скорее что-то вроде "Массив элементов типа ptr на первый эл-т объекта "Три эл-та типа int*" (далее для краткости "МассивPtrTo3Int*").

Тогда #2:
2.1) b - из объекта "МассивPtrTo3Int*" неявно --> в ptr на первый его эл-т - т.е. в ptr на 1й эл-т объекта "3 эл-та типа int*"
2.2) процедура адресации `[1]` выполняет сдвиг и разыменование: сдвиг переносит нас к ptr'у на 1й эл-т второго объекта "3 эл-та типа int*", а разыменование --> это к 1-ому из эл-тов типа int*
2.3) Последнее действие явно указанного разыменования даёт нам его значение - "55".

Не стану уже Вас утомлять, но под эту логику согласованно ложится и вариант #1.

Кажется, я суть почти ухватил, только как-то немного расплывчато и нечётко получилось выразить.

Повторюсь:
Буду очень благодарен, если кто-то сможет указать на ошибки в рассуждении и, ГЛАВНОЕ, конкретизировать, как всё-таки устроен логически внутри себя многомерный массив в C++ и в какие моменты происходят в нём неявные преобразования.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.12.2014, 12:15
Ответы с готовыми решениями:

Преобразование имени массива в указатель
Привет всем, почему такое присваивание не вызывает ошибки int (*x) ; ...

Cоздание многомерного массива - из 3х3 массива сделать 4х3
Создать многомерный массив 4x3 элементов. По данному примеру. Пример. Код...

Внутреннее устройство потоков
Очень тупой вопрос - почему std::ios хранит в своих потрохах указатель на...

Приведение любого двумерного массива к типу указатель на указатель
Допустим, есть несколько массивов int arr1; int arr2; int arr3; Какое...

Сортировка многомерного массива.
Здравствуйте! Помогите пожалуйста с решением такой задачи. Я еще совсем...

22
NotNot
30 / 30 / 6
Регистрация: 23.10.2014
Сообщений: 107
20.12.2014, 13:50 2
У операций есть приоритеты. Операция взятия по индексу имеет больший приоритет, нежели операция разыменования т.е *b[i] == *(b[i]), ну и:
C++
1
2
3
4
 b: int **
*b: int *
 b[i] == *(b + i): int *
*b[i] == *(*(b + i)): int
0
Mr.X
Эксперт С++
3182 / 1709 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
20.12.2014, 14:12 3
Цитата Сообщение от SaShka K Посмотреть сообщение
как всё-таки устроен логически внутри себя многомерный массив в C++ и в какие моменты происходят в нём неявные преобразования?
Цитата Сообщение от SaShka K Посмотреть сообщение
C++
1
2
3
int b [2][3] = {{11,22,33}, {55,66,77}};
/*#1*/ cout<< (*b)[1]; //out: 22
/*#2*/ cout<< *b[1]; //out: 55
А чего тут непонятного?
Имя массива может использоваться как указатель на его первый элемент.
В #1 b - это указатель на первый трехмерный массив целых. *b - это сам этот массив. Далее выводим его элемент с индексом 1.
В #2 индексируем b, т.е. указатель на первый трехмерный массив целых и получаем второй трехмерный массив, который можно использовать как указатель на его первый элемент, т.е. 55. Выводим разыменование этого указателя, т.е. само число 55.
0
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
20.12.2014, 14:30  [ТС] 4
@Mr.X, в таком масштабе мне это вроде понятно. Вся же куча написанного текста - попытка разобраться в этих процессах в более мелких деталях. Большей частью, увязать с тем фактом, что `b` на самом деле - это вроде как объект "массив", который при таком обращении претерпевает неявное преобразование к указателю на свой 1й элемент (такого преобразования, например, не происходит при обращении в выражении взятия адреса `&b`). Прочёл об этом в заморской теме "array to pointer conversion" или как они это ещё называют "decay into ptr".

Вот пытаюсь понять, каждый ли уровень многомерного массива является таким же объектом, которому часто грозит "разложение в указатель" и в какой именно момент это разложение происходит в выражениях.

Добавлено через 2 минуты
@NotNot, это очевидные для меня вещи. Вопрос же совсем в другом.
0
NotNot
30 / 30 / 6
Регистрация: 23.10.2014
Сообщений: 107
20.12.2014, 16:02 5
SaShka K, приглашаю вас почитать Страуструпа. The Programming Language C++ 4-е издание. В частности, седьмую главу.

Добавлено через 31 минуту
http://ideone.com/VbnzJF
Хе-хе. Мои представления были не верны.
0
Mr.X
Эксперт С++
3182 / 1709 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
20.12.2014, 16:36 6
Цитата Сообщение от SaShka K Посмотреть сообщение
объект "массив"
Ну, "объект" здесь один - это одномерный массив, записанный в память именно так, как вы указали в инициализаторе. Вся многомерность организуется через игру с указателями, что сделано, как и все с Си, через задницу. Сишный массив - это такой же "недотип", как и сишная нультерминальная строка.
У меня вот не хватает несерьезности, чтобы относиться к этим вещам серьезно. Мне кажется, что нужно быть проще, и использовать векторы и std::array, а копаться в этой нетрезвой зауми предоставить сишникам, благо они это любят.
0
lss
930 / 859 / 355
Регистрация: 10.10.2012
Сообщений: 2,705
20.12.2014, 17:27 7
Цитата Сообщение от SaShka K Посмотреть сообщение
как всё-таки устроен логически внутри себя многомерный массив в C++ и в какие моменты происходят в нём неявные преобразования.
Такой массив:
C++
1
int b [2][3];
можно так представить (возможно, так понятней будет.):
C++
1
int (*b)[3]; // указатель на одномереый массив из 3-х элементов.
Цитата Сообщение от SaShka K Посмотреть сообщение
1.1) b - неявно преобразуется (далее -->) из объекта "2D-массив" - в ptr на первый его эл-т - т.е. в ptr на 1D-массив элементов типа int*
Только: на 1D-массив элементов типа int, а не int*.

Добавлено через 29 минут
C++
1
2
3
4
5
6
    int b[2][3] = {{1, 2, 3}, {4, 5, 6}};
    cout << b << endl << *b << endl << b[0] << endl;
    cout << (*b)[1] << endl << b[0][1] << endl << *((*b) + 1) << endl << *(b[0] + 1);
    cout << endl << endl;
    cout << b + 1 << endl << *(b + 1) << endl << b[1] << endl;
    cout << (*(b + 1))[1] << endl << b[1][1] << endl << *(*(b + 1) + 1) << endl << *(b[1] + 1);
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
20.12.2014, 18:04  [ТС] 8
Цитата Сообщение от lss Посмотреть сообщение
Originally Posted by SaShka K
1.1) b - неявно преобразуется (далее -->) из объекта "2D-массив" - в ptr на первый его эл-т - т.е. в ptr на 1D-массив элементов типа int*
Только: на 1D-массив элементов типа int, а не int*.
Верно! Спасибо. Вот тут я заблудился.
Действительно:
int i = 1;
//тип i - int
int a [3] = {11,22,33};
//тип a - 1D-массив int'ов (неявно распадается в ptr на 1й эл-т - т.е. в int*)
int b [2][3] = {{11,22,33}, {55,66,77}};
//тип b - 2D-массив int'ов, т.е. 1D-массив 1D-массивов int'ов (неявно распадается в ptr на 1й эл-т - т.е. в int(*)[])
Тогда получается:
#1:
1.1) неявно `b` --> в int(*)[3]
1.2) разыменование даёт int[3] (объект 1D-субмассив 1ой строки)
1.3) который неявно --> в int* (указатель на 1й элемент)
1.4) адресация даёт сдвиг и разыменование - получаем "22"

#2:
2.1) то же самое
2.2) адресация (т.е. сдвиг + разыменование) - получаем int[3] (субмассив второй строки)
2.3) неявно --> в int* (указатель на 1й элемент)
2.4) после разыменования - "55"

Вроде всё сходится и логика теперь похожа на чёткую!

Но Вы натолкнули на другой вопрос:
Цитата Сообщение от lss Посмотреть сообщение
можно так представить (возможно, так понятней будет.):
Код C++
1
int (*b)[3]; // указатель на одномереый массив из 3-х элементов.
Какова же тогда роль первого измерения `b[2][3]` (в частности его размера), которая в данном случае оказывается "за кадром"?

Добавлено через 3 минуты
@NotNot, спасибо за Вашу активность, но всё ещё не вижу, как она может приблизить меня к ответу на поставленный вопрос:
- главу просмотрел (издания 4 не имею, но в 3ем она под №5 с тем же названием) - в ней только базовые сведения - ничего нового для себя (в т.ч. по своему вопросу не встретил).

- код по ссылке посмотрел - забавно, но не понял, как он отвечает на мой вопрос.
0
lss
930 / 859 / 355
Регистрация: 10.10.2012
Сообщений: 2,705
20.12.2014, 18:28 9
Цитата Сообщение от SaShka K Посмотреть сообщение
Какова же тогда роль первого измерения `b[2][3]` (в частности его размера), которая в данном случае оказывается "за кадром"?
В общем-то, никакая. Поэтому такой массив в функцию можно так передавать:
C++
1
2
3
4
5
6
7
void foo(int b[][3])
{
    
}
 
int b[2][3] = {{1, 2, 3}, {4, 5, 6}};
foo(b);
При разложении имени массива в указатель (в параметрах функции), первая граница массива тоже разлагается (теряется), в отличие от следующих границ (в противном случае невозможно было бы применять арифметику указателей к формальным параметрам).
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
20.12.2014, 18:38  [ТС] 10
@lss, касательно последнего Вашего кода.
Именно то, что `cout<< b;` и `cout<< *b;` дают одинаковый результат и привело меня к теме неявного преобразования от объекта массив к указателю на его 1й элемент. А попытки разобраться, когда именно это преобразование происходит (и сколько таких объектов "массив", способных претерпеть его, заключено внутри многомерного массива) привели к написанию этого поста.
Что я благодаря Вам попробую заключить:
  • таких объектов столько же, сколько и измерений у многомерного массива
  • неявное преобразование в указатель на свой 1й элемент объект "массив" претерпевает в тот момент, как только анализатор выражения при его разборе начинает оперировать такой сущностью (освобождённой от любых заключающих её в себе конструкций). Т.е., глядя на разбор #1, пока у нас субмассив - строка как объект была запрятана в глубинах выражения (*b)[1]; то ни о каких её преобразованиях речи не шло, но как только анализатор выражения в конце шага 1.2 дорыл до того, что получил эту сущность как объект, то тут же происходит шаг 1.3 - этого самого неявного преобразования.
Кажется теперь очень похоже на правду, хотя быть может я всё ещё заблуждаюсь? (буду благодарен за корректировки)
0
lss
930 / 859 / 355
Регистрация: 10.10.2012
Сообщений: 2,705
20.12.2014, 18:48 11
Цитата Сообщение от SaShka K Посмотреть сообщение
(и сколько таких объектов "массив", способных претерпеть его, заключено внутри многомерного массива)
Цитата Сообщение от SaShka K Посмотреть сообщение
таких объектов столько же, сколько и измерений у многомерного массива
Такой объект один - имя массива. Сколько в этом массиве содержится других массивов неважно. Компилятору нужен адрес начала многомерного массива (в который разлагается имя массива) и размерности массивов, которые он содержит, чтобы
Цитата Сообщение от lss Посмотреть сообщение
применять арифметику указателей
0
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
20.12.2014, 19:01  [ТС] 12
@lss, получается, что в области видимости, в рамках которой объявлен, скажем, XD-массив, существует объект "XD-массив", у которого есть атрибут значения каждой из X размерностей. Когда же мы передаём его в функцию, то XD-массив распадается в указатель на (X-1)D-массив, теряя и 1 атрибут своей размерности верхнего уровня.
(просто пытаюсь немного систематизировать)

Добавлено через 5 минут
Если
Цитата Сообщение от lss Посмотреть сообщение
Такой объект один
, то что-то неверно (а именно шаги 1.3 и 2.3) в моей последней интерпретации пошагового разбора выражений ##1 и 2:
Цитата Сообщение от SaShka K Посмотреть сообщение
Тогда получается:
#1:
1.1) неявно `b` --> в int(*)[3]
1.2) разыменование даёт int[3] (объект 1D-субмассив 1ой строки)
1.3) который неявно --> в int* (указатель на 1й элемент)
1.4) адресация даёт сдвиг и разыменование - получаем "22"

#2:
2.1) то же самое
2.2) адресация (т.е. сдвиг + разыменование) - получаем int[3] (субмассив второй строки)
2.3) неявно --> в int* (указатель на 1й элемент)
2.4) после разыменования - "55"
Добавлено через 3 минуты
Цитата Сообщение от Mr.X Посмотреть сообщение
Мне кажется, что нужно быть проще, и использовать векторы и std::array,
Так то оно так, но в критичных по производительности фрагментах std-контейнеры заметно эту самую производительность просаживают.
0
lss
930 / 859 / 355
Регистрация: 10.10.2012
Сообщений: 2,705
20.12.2014, 19:57 13
Цитата Сообщение от SaShka K Посмотреть сообщение
просто пытаюсь немного систематизировать
Я предлагаю проще. Когда объявляется такой массив:
C++
1
int b[2][3];
на стеке выделяется область памяти под шесть int-ов. Чтобы перемещаться по этой памяти (с помощью индексов или арифметики указателей (что одно и тоже), компилятору нужно знать адрес начала этой памяти (что и происходит при разложении имени массива в указатель) и размерность одномерных массивов (которую он извлекает из объявления массива или из формального параметра функции, при передаче такого массива в функцию). Размер выделенной памяти под массив компилятор не знает (знает только, что там int-ы), первая размерность ему не нужна, величину индексов, при перемещении по массиву, он не отслеживает, поэтому выходы за границы массива компилятором не отслеживаются.

Добавлено через 7 минут
Цитата Сообщение от SaShka K Посмотреть сообщение
1.2) разыменование даёт int[3] (объект 1D-субмассив 1ой строки)
Вот если не так:
C++
1
(*b)[1];
а по другому:
C++
1
*((*b) + 1)
Разыменование b даёт адрес int-a, а не int[3]. Для перехода к следующему int-у, к этому адресу прибавляется единица, т.е. исходя из арифметики указателей, размер одного int-а.
1
Mr.X
Эксперт С++
3182 / 1709 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
20.12.2014, 20:15 14
Цитата Сообщение от SaShka K Посмотреть сообщение
Так то оно так, но в критичных по производительности фрагментах std-контейнеры заметно эту самую производительность просаживают.
Может оно и так, но отсюда не следует, что сишные массивы нужно называть объектами и искать в них какую-то скрытую мудрость, которой в них сроду не было.
А с std::array сравнивали по скорости?
0
NotNot
30 / 30 / 6
Регистрация: 23.10.2014
Сообщений: 107
20.12.2014, 20:38 15
SaShka K, в главе, что я вам посоветовал, сказано, что двумерный массив, на самом деле, является одномерным массивом, а вся мерность присутствует только в исходном коде. Это утверждение и проверяет код который я предоставил. Также, в этой главе, говорится о такой вещи как: "a[b] == *(a + b) == *(b + a) == b[a]", где 'a' имеет тип int[n], а 'b' имеет тип int, что говорит о том что компилятору без разницы a[b] или b[a]. Он всегда преобразует записть вида a[b] к виду *(a + b), что, в свою очередь говорит о том что имя массива всегда преобразуется к указателю, а вот тип указателя уже зависит от размерности массива.

Теперь рассмотрим массив 'int a[n][k]'. К слову, 'a', вне каких либо операций имеет тип int[n][k].

1. Рассмотрим операцию (*a)[i].

При разыменовании, 'a', неявно, преобразуется к int (*)[k]. В свою очередь, разыменование этого указателя даёт нам массив int[k]. Назовем его 'b'. Значит (*a)[i] -> b[i]. Во что превратится b[i] мы знаем: *(b + i), где 'b', неявно, преобразуется в int *.

2. Рассмотрим операцию *a[i], что, по сути, тоже самое что и *(a[i]).

Операция a[i] дает нам массив int[k]. Назовем его 'b'. Значит *(a[i]) -> *b. При разыменовании, 'b', неявно, преобразуется в int*, который равен &b[0], и его разыменование дает нам int, который b[0], т.е первый элемент i-го подмассива массива 'a'.

А теперь подумаем. Если b[i], где b: int[n], преобразуется в *(b + i), тогда может и a[i][j] преобразуется в нечто подобное? Действительно: a[i][j] -> (*(a + i))[j], где 'a' это - int (*)[k], и (*(a + i))[j] -> *(*(a + i) + j), где *(a + i) это - int[k], т.е a[i][j] -> *(*(a + i) + j).
1
Croessmah
++Ͻ
14740 / 8422 / 1597
Регистрация: 27.09.2012
Сообщений: 20,714
Записей в блоге: 2
Завершенные тесты: 1
20.12.2014, 20:50 16
Чтобы было на форуме
8.3.4 Arrays
1.
In a declaration T D where D has the form
D1 [ constant-expressionopt ] attribute-specifier-seqopt
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is an array type; if the type of the identifier of D contains the auto type-specifier , the program is ill-formed. T is called the array element type; this type shall not be a reference type, the (possibly cv-qualified) type void, a function type or an abstract class type. If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero. The constant expression specifies the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N elements numbered 0 to N-1, and the type of the identifier of D is “ derived-declarator-type-list array of N T”. An object of array type contains a contiguously allocated non-empty set of N subobjects of type T. Except as noted below, if the constant expression is omitted, the type of the identifier of D is “ derived-declarator-type-list array of unknown bound of T”, an incomplete object type. The type “ derived-declarator-type-list array of N T” is a different type from the type “ derived-declarator-type-list array of unknown bound of T”, see 3.9. Any type of the form “ cv-qualifier-seq array of N T” is adjusted to “array of N cv-qualifier-seq T”, and similarly for “array of unknown bound of T”. The optional attribute-specifier-seq appertains to the array. [ Example:
C++
1
2
3
typedef int A[5], AA[2][3];
typedef const A CA;// type is “array of 5 const int”
typedef const AA CAA;// type is “array of 2 array of 3 const int”
— end example ] [ Note: An “array of N cv-qualifier-seq T” has cv-qualified type; see 3.9.3. — end note ]
2.
An array can be constructed from one of the fundamental types (except void), from a pointer, from a pointer to member, from a class, from an enumeration type, or from another array.
3.
When several “array of” specifications are adjacent, a multidimensional array is created; only the first of the constant expressions that specify the bounds of the arrays may be omitted. In addition to declarations in which an incomplete object type is allowed, an array bound may be omitted in some cases in the declaration of a function parameter (8.3.5). An array bound may also be omitted when the declarator is followed by an initializer (8.5). In this case the bound is calculated from the number of initial elements (say, N) supplied (8.5.1), and the type of the identifier of D is “array of N T.” Furthermore, if there is a preceding declaration of the entity in the same scope in which the bound was specified, an omitted array bound is taken to be the same as in that earlier declaration, and similarly for the definition of a static data member of a class.
4.
[ Example:
C++
1
float fa[17], *afp[17];
declares an array of float numbers and an array of pointers to float numbers. For another example,
C++
1
static int x3d[3][5][7];
declares a static three-dimensional array of integers, with rank 3 × 5 × 7. In complete detail, x3d is an array of three items; each item is an array of five arrays; each of the latter arrays is an array of seven integers. Any of the expressions x3d, x3d[i], x3d[i][j], x3d[i][j][k] can reasonably appear in an expression. Finally,
C++
1
2
3
4
5
6
7
8
9
10
extern int x[10]
struct S {
static int y[10];
};
int x[];;// OK: bound is 10
int S::y[];// OK: bound is 10
void f() {
extern int x[];
int i = sizeof(x);// error: incomplete object type
}
— end example ]
5.
[ Note: conversions affecting expressions of array type are described in 4.2. Objects of array types cannot be modified, see 3.10. — end note ]
6.
[ Note: Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.
7.
A consistent rule is followed for multidimensional arrays. If E is an n-dimensional array of rank i×j ×. . .×k, then E appearing in an expression that is subject to the array-to-pointer conversion (4.2) is converted to a pointer to an (n − 1)-dimensional array with rank j × . . . × k. If the * operator, either explicitly or implicitly as a result of subscripting, is applied to this pointer, the result is the pointed-to (n − 1)-dimensional array, which itself is immediately converted into a pointer.
8.
[ Example: consider
C++
1
int x[3][5];
Here x is a 3 × 5 array of integers. When x appears in an expression, it is converted to a pointer to (the first of three) five-membered arrays of integers. In the expression x[i] which is equivalent to *(x+i), x is first converted to a pointer as described; then x+i is converted to the type of x, which involves multiplying i by the length of the object to which the pointer points, namely five integer objects. The results are added and indirection applied to yield an array (of five integers), which in turn is converted to a pointer to the first of the integers. If there is another subscript the same argument applies again; this time the result is an integer. — end example ] — end note ]
9.
[ Note: It follows from all this that arrays in C ++ are stored row-wise (last subscript varies fastest) and that the first subscript in the declaration helps determine the amount of storage consumed by an array but plays no other part in subscript calculations. — end note ]
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
22.12.2014, 22:55  [ТС] 17
@lss, спасибо за Ваше участие в обсуждении! Перфекционист во мне продолжил бы дискуссию, но, к счастью, рационалист ему намекает =), что суть уже схвачена, а доведение деталей до блеска будет уже гораздо больше есть времени, чем приносить пользы.

Добавлено через 7 минут
@Mr.X, да я ж ничего не выдумывал сам - про "объект" и далее про его распад в указатель - это я начитался в иностранных интернетах. Просто хотелось разобраться, потому как мне как-то гораздо спокойнее живётся, когда понимаю, почему что-то именно таково, каким оно есть, а не пытаюсь запомнить магические рецепты.(но это лично моё восприятие).

Касательно std::array - помню, что экспериментировал устраивать гонки сортировкам кажется с использованием std и избегая его. (но, кажется пользовался vector'ом) - помню, что код с std существенно проигрывал.
Сейчас проверил что-то подобное с std::array - проигрывает в 3..5 раз. (но не стал докапываться пока, чтобы разобрать по операциям - какие именно приводят к этим задержкам)

Добавлено через 15 минут
@NotNot, спасибо за разъяснения - наконец понял Вас.
Я пытался размышлять немного в другом ключе (но тут проблема во мне - вопрос сформулировал не слишком однозначно), но эта информация тоже интересна весьма и полезна для получения общей картинки.

PS: в книжке то, о чём Вы сейчас подробнее сказали (в моём 3-ем издании) написано в приложении В.7. ("Многомерные массивы"), на которое в главе №5 ("Указатели, массивы и структуры") есть ссылка.
0
Mr.X
Эксперт С++
3182 / 1709 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
22.12.2014, 23:42 18
Цитата Сообщение от SaShka K Посмотреть сообщение
да я ж ничего не выдумывал сам - про "объект"
Объект - это область памяти, хранящая данные некоторого типа. Сишный массив не является полноценным типом, поэтому и объектов в их нормальном понимании иметь не может.
0
rat0r
4 / 52 / 10
Регистрация: 16.02.2018
Сообщений: 271
22.04.2018, 01:08 19
Цитата Сообщение от Croessmah Посмотреть сообщение
Objects of array types cannot be modified
C++
1
2
int a[2] = { 0, 2, };
a[1] = 1;
Вот, я модифицировал массив a.
0
Croessmah
++Ͻ
14740 / 8422 / 1597
Регистрация: 27.09.2012
Сообщений: 20,714
Записей в блоге: 2
Завершенные тесты: 1
22.04.2018, 05:51 20
rat0r, поесть хочешь?
0
22.04.2018, 05:51
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.04.2018, 05:51

Обработка многомерного массива
Помогите пожалуйста Известно количество сделанных столов тремя фабриками за...

Return многомерного массива
не понимаю как передавать многомерные массивы в c++. есть массив char arr...

Передача массива в метод без возможности изменить внутреннее состояние
Доброго всем времени суток! Разрабатываю систему, в которой понадобилось...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru