Массив для разметки указателя и передачи многомерных массивов в функции
Я знаю, что массив распадается на указатель, так что если объявить
char things[8];
а затем при использовании things
где-то еще, things
является указателем на первый элемент в массиве.
Кроме того, из моего понимания, если объявить
char moreThings[8][8];
тогда moreThings
не имеет указателя на тип char, а типа "массив указателей на char", потому что распад происходит только один раз.
Когда moreThings
передается функции (скажем, с прототипом void doThings(char thingsGoHere[8][8])
, что на самом деле происходит со стеком?
Если moreThings
не относится к типу указателя, то это действительно все-таки перекрестная ссылка? Думаю, я всегда думал, что moreThings
все еще представляет собой базовый адрес многомерного массива. Что, если doThings
принял вход thingsGoHere
и сам передал его другой функции?
Правильно ли это правило, что, если не указать вход массива как const
, тогда массив всегда будет изменяться?
Я знаю, что материал проверки типов происходит только во время компиляции, но я все еще смущен тем, что технически считается передачей по ссылке (т.е. только когда передаются аргументы указателя типа или массив массивов указателей также и пропуская ссылку?)
Прошу прощения за то, что у меня есть вопрос, но из-за моей трудности в понимании этого трудно сформулировать точный запрос.
Ответы
Ответ 1
У вас это немного неверно: moreThings
также распадается на указатель на первый элемент, но поскольку он представляет собой массив массива символов, первый элемент представляет собой "массив из 8 символов". Таким образом, разлагающийся указатель относится к этому типу:
char (*p)[8] = moreThings;
Значение указателя, конечно, совпадает с значением &moreThings[0][0]
, то есть первого элемента первого элемента, а также тем же значением &a
, но тип в каждом случае является другим.
Вот пример, если char a[N][3]
:
+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
| a[0] | a[1] |
+===========================+===========================+====
a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
-
&a
: адрес всего массива массивов символов, который является char[N][3]
-
&a[0]
, то же, что и a
: адрес первого элемента, который сам является char[3]
-
&a[0][0]
: адрес первого элемента первого элемента, который является char
Это показывает, что разные объекты могут иметь один и тот же адрес, но если два объекта имеют один и тот же адрес и один и тот же тип, то они являются одним и тем же объектом.
Ответ 2
"АДРЕС МАССИВА И УКАЗЫВАЕТСЯ МНОГОМЕРНЫМ МАССАМ"
Давайте сначала начнем с 1-D массива:
-
Объявление char a[8];
создает массив из 8 элементов.
И здесь a
есть адрес элемента , но не адрес массива.
-
char* ptr = a;
является правильным выражением, поскольку ptr
является указателем на char и может обращаться к первому элементу.
-
Но выражение ptr = &a
неверно! Поскольку ptr
не может адресовать массив.
-
и означает адрес массива. Действительное значение a
и &a
одинаково, но семантически оба разные, один является адресом char other - адресом массив из 8 символов.
-
char (*ptr2)[8];
Здесь ptr2 is pointer to an array of 8 chars
, и на этот раз
ptr2=&a
является допустимым выражением.
-
Тип данных &a
равен char(*)[8]
, а тип a
- char[8]
, который просто распадается на char*
в большинстве операций, например. char* ptr = a;
Чтобы лучше понять: Разница между char *str
и char str[]
и как оба хранилища в памяти?
Второй случай,
-
Объявление char aa[8][8];
создает 2-мерный массив размера 8x8
.
-
Любой 2-D массив также можно рассматривать как 1-D массив, в котором каждый элемент массива представляет собой 1-D массив.
-
aa
- это адрес первого элемента, который представляет собой массив из 8 символов. Выражение ptr2 = aa
является правильным и правильным.
-
Если мы заявляем следующее:
char (*ptr3)[8][8];
char ptr3 = &aa; //is a correct expression
Аналогично,
moreThings
в объявлении char moreThings[8][8];
содержит адрес элемента fist, который представляет собой массив char из 8 элементов.
Чтобы лучше понять: Разница между char* str[]
и char str[][]
и как оба хранилища в памяти?
Было бы интересно узнать:
-
morething
- это адрес массива 8 char.
-
*morething
- это адрес первого элемента, который &morething[0][0]
.
-
&morething
- адрес 2-мерного массива 8 x 8.
И значения адреса всех выше трех одинаковы, но семантически все разные.
-
**morething
- значение первого элемента, который morething[0][0]
.
Чтобы лучше понять: Разница между &str
и str
, когда str
объявлен как char str[10]
?
Далее,
-
void doThings(char thingsGoHere[8][8])
- не что иное, как void doThings(char (*thingsGoHere)[8])
и, таким образом, принимает любой массив, который является двумерным, а второй размер равен 8.
О типе переменных в C и С++: (я бы хотел добавить в ответ)
- Ничто не пропускает по ссылке в C концепцию С++. Если его использовать в C, это означает, что автор говорит о переменной указателя.
- C поддерживает
pass by Address
и pass by value
.
-
С++ поддерживает pass by Address
, pass by value
, а также pass by Reference
.
Читайте: указательные переменные и ссылочные переменные
В конце,
- Имя массива - это постоянный идентификатор, а не переменный.
Ответ 3
Хорошо объяснено Kerrek,
В дополнение к этому мы можем доказать это в следующем примере:
#include <stdio.h>
int main ()
{
int a[10][10];
printf (".. %p %p\n", &a, &a+1);
printf (".. %p %p \n ", &a[0], &a[0]+1);
printf (".. %p %p \n ", &a[0][0], &a[0][0] +1);
}
Выход:
.. 0x7fff6ae2ca5c 0x7fff6ae2cbec = 400 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca84 = 40 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca60 = 4 bytes difference.
& a +1 → Перемещает указатель, добавляя размер всего массива. т.е.: 400 байт
& a [0] + 1 → Перемещает указатель, добавляя размер столбца. т.е.: 40 байт.
& a [0] [0] +1 → Перемещает указатель, добавляя размер элемента ie: 4 байта.
[int size is 4 bytes]
Надеюсь, это поможет.:)