Массив для затухания указателя и передачи многомерных массивов в функции
Я знаю, что массив распадается на указатель, так что если один объявил
char things[8];
а потом использовал things
где-нибудь еще, things
указатель на первый элемент в массиве
Кроме того, насколько я понимаю, если
char moreThings[8][8];
затем moreThings
не имеет указатель типа на символ, но имеет тип "массив указателей на символ", потому что затухание происходит только один раз.
когда moreThings
передается в функцию (скажем, с прототипом void doThings(char thingsGoHere[8][8])
что на самом деле происходит со стеком?
Если moreThings
это не указатель типа, то действительно ли это все еще передача по ссылке? Я думаю, я всегда думал, что moreThings
по-прежнему представляет базовый адрес многомерного массива. Что, если doThings
принял вход thingsGoHere
а сам передал это другой функции?
Является ли правило в значительной степени тем, что если не указать вход массива как const
тогда массив всегда будет изменяемым?
Я знаю, что проверка типов происходит только во время компиляции, но я все еще не понимаю, что технически считается передачей по ссылке (т. Е. Происходит ли это только тогда, когда передаются аргументы указателя типа, или массив указателей будет проходным по ссылке тоже?)
Извините, что был немного повсюду с этим вопросом, но из-за моих трудностей в понимании этого трудно сформулировать точный вопрос.
3 ответа
Вы немного ошиблись 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
Это демонстрирует, что разные объекты могут иметь один и тот же адрес, но если два объекта имеют один и тот же адрес и один и тот же тип, то это один и тот же объект.
"АДРЕС МАРШРУТА И УКАЗАТЕЛИ НА МНОГОМЕРНЫЕ МЕРЫ"
Давайте сначала начнем с 1-D массива:
декларация
char a[8];
создает массив из 8 элементов.
И здесьa
это адрес первого элемента, но не адрес массива.char* ptr = a;
правильное выражение какptr
является указателем на символ и может адресовать первый элемент.Но выражение
ptr = &a
это неправильно! Так какptr
не может обратиться к массиву.& адрес средства массива. Действительно ценность
a
а также&a
одинаковы, но семантически оба различны, один - адрес символа, другой - адрес массива из 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];
создает двумерный массив8x8
размер.Любой двумерный массив также можно рассматривать как одномерный массив, в котором каждый элемент массива является одномерным массивом.
aa
это адрес первого элемента, который является массивом из 8 символов. выражениеptr2 = aa
является действительным и правильным.Если мы объявим следующее:
char (*ptr3)[8][8]; char ptr3 = &aa; //is a correct expression
Так же,
moreThings
в вашей декларацииchar moreThings[8][8];
содержит адрес первого элемента, который является массивом из 8 элементов.Чтобы понять лучше читать: разница между
char* str[]
а такжеchar str[][]
а как оба хранятся в памяти?
Было бы интересно узнать:
morething
адрес массива из 8 символов*morething
это адрес первого элемента, который&morething[0][0]
,&morething
это адрес двумерного массива 8 х 8.И значения адресов всех трех выше одинаковы, но семантически все различны.
**morething
это значение первого элемента, которыйmorething[0][0]
,Чтобы понять лучше читать: разница между
&str
а такжеstr
, когдаstr
объявлен какchar str[10]
?
Дальше больше,
void doThings(char thingsGoHere[8][8])
не что иное, как пустотаdoThings(char (*thingsGoHere)[8])
и таким образом принимает любой массив, который является двумерным со вторым измерением, равным 8.
О типе переменных в C и C++: (Я хотел бы добавить в ответ)
- Ничто не передается по ссылке в C его концепции C++. Если это используется в C, это означает, что автор говорит о переменной указателя.
- C поддерживает
pass by Address
а такжеpass by value
, C++ поддерживает
Pass by address
,pass by value
а такжеpass by Reference
,
В конце,
- Имя массива является постоянным идентификатором, а не переменным.
Хорошо объяснил Керрек,
В дополнение к этому мы можем доказать это на следующем примере:
#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 -> Перемещает указатель, добавляя размер элемента, т.е. 4 байта.
[размер int 4 байта]
Надеюсь это поможет.:)