Это мой первый вопрос :)
double MyArray[][6];
double* Myptr = MyArray[0];
Поэтому мне было интересно, почему, в указателе Arithmetic, я могу обозначить указатель на перемещение в одном измерении, как это,
*(Myptr + i);
но если я попытаюсь перемещаться по размерам массива с помощью цикла for, это не позволит мне
*(*(Myptr + i) + j);
Однако это позволяет мне использовать это обозначение с самим массивом.
*(*(MyArray + i) + j);
Я хотел знать, почему это ограничение? или, может быть, я неправильно его записываю.
Myptr
- это указатель на double, поэтому *(Myptr + i)
является двойным, и, хотя вы можете добавить j
к этому, вы не можете разыгрывать результат.
Если бы вы объявили Myptr
следующим образом:
double (*Myptr)[6] = MyArray;
то Myptr
будет указателем на массив из 6 double
s. Следовательно, *(Myptr + i)
будет double[6]
, и выражение будет работать.
То, что вы можете индексировать массивы с использованием этого синтаксиса, к сожалению, удивительно для людей, которые видят его в первый раз и никогда не учили о разложении указателя. Самое забавное в массивах на C и C++ заключается в том, что они распадаются на указатели практически во всех обстоятельствах. Это означает, что почти всегда, когда вы используете массив (существуют исключения), массив неявно преобразуется в указатель на его первый элемент, а остальное выполняется с помощью арифметики указателя.
Например, это так, когда вы пишете MyArray[i]
. Стандарт определяет MyArray[i]
как означающий *(MyArray + i)
(стандарт использует больше скобок, но это то, к чему это сводится), что имеет смысл, когда вы понимаете, что MyArray
распадается на указатель, i
добавляется к этому указатель, и полученный указатель разыменовывается. Это также объясняет, почему i[MyArray]
одинаково действителен (если в плохом стиле).
В контексте многомерных массивов важно понимать, что многомерный массив является всего лишь массивом массивов. MyArray
- это, в вашем случае, массив массивов двойников. MyArray[0]
является массивом двойников. При расчете указателя MyArray
распадается на указатель на массив двойников, а когда вы разыскиваете этот указатель и работаете с массивом, который он указывает, то этот массив также распадается на указатель (в два раза) при работе с ним. Он распадается весь путь вниз.
MyArray имеет тип double[][6]
а MyPointer имеет тип double*
.
Теперь массивы и указатели разные, но это не важно в этом контексте. Обе переменные имеют типы массивов/указателей в своих типах, но My Array имеет два (считать их: []
и [6]
), а MyPointer имеет только один (считайте: *
). Вот почему вы можете применять разыменование (что оператор *
) для MyArray дважды, а MyPointer - только один раз.
Теперь, если вы хотите иметь указатель, который можно использовать почти так же, как вы используете MyArray, это возможно, но его тип не будет double**
(поскольку массивы и указатели разные). Вы пишете это так:
double (*MyPointer2)[6] = MyArray;
У этого есть два типа массива/указателя в его типе, чтобы вы могли применить к нему разыменование дважды.
В этом случае MyPtr имеет только один размер, потому что он был назначен определенному "массиву" в MyArray.
Потому что Myptr
является double*
. Указатель на двойной. Он не знает размеры массива.