Массив для разметки указателя и передачи многомерных массивов в функции

Я знаю, что массив распадается на указатель, так что если объявить

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]

Надеюсь, это поможет.:)