数组指针衰减并将多维数组传递给函数

lla*_*ais 10 c arrays callstack pointers multidimensional-array

我知道一个数组衰减到指针,如果一个声明

char things[8];
Run Code Online (Sandbox Code Playgroud)

然后在things其他地方使用,things是一个指向数组中第一个元素的指针.

另外,根据我的理解,如果有人宣称

char moreThings[8][8];
Run Code Online (Sandbox Code Playgroud)

那么moreThings不是指向char的类型指针,而是类型为"指向char的指针数组",因为衰减只发生一次.

什么时候moreThings传递给一个函数(比如说原型void doThings(char thingsGoHere[8][8])实际上是什么进行了堆栈?

如果moreThings不是指针类型,那么这仍然是一个传递引用?我想我一直认为它moreThings仍然代表了多维数组的基地址.如果doThings接受输入thingsGoHere并将其传递给另一个函数会怎么样?

规则几乎是除非指定数组输入,const然后数组将始终可修改?

我知道类型检查的东西只发生在编译时,但我仍然对技术上作为一个引用传递的东西感到困惑(即只有当传递类型指针的参数时,或者指针数组是否为传递 - 参考也是?)

很抱歉这个问题在这个地方有点儿,但由于我很难理解这一点,很难说出一个精确的询问.

Ker*_* SB 22

你有点错误:moreThings也衰减到指向第一个元素的指针,但由于它是一个字符数组的数组,第一个元素是"8个字符数组".所以腐朽的指针属于这种类型:

char (*p)[8] = moreThings;
Run Code Online (Sandbox Code Playgroud)

指针的当然与&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
Run Code Online (Sandbox Code Playgroud)
  • &a:字符数组的整个数组的地址,这是一个 char[N][3]

  • &a[0],同样如下a:第一个元素的地址,它本身就是一个char[3]

  • &a[0][0]:第一个元素的第一个元素的地址,即a char

这表明不同的对象可能具有相同的地址,但如果两个对象具有相同的地址相同的类型,则它们是相同的对象.


Gri*_*han 13

"阵列地址和指向多维阵列的指针"

让我们先从1-D阵列开始:

  • 声明char a[8];创建一个包含8个元素的数组.
    这里a第一个元素的地址不是数组的地址.

  • char* ptr = a;ptr指向char的正确表达式,可以解决第一个元素.

  • 但表达ptr = &a错误的!因为ptr无法解决数组问题.

  • &a表示数组的地址.真正的值a&a相同但在语义上都是不同的,一个是char的地址,另一个是8个字符的数组的地址.

  • char (*ptr2)[8]; 在这里ptr2 is pointer to an array of 8 chars,这次 ptr2=&a是一个有效的表达.

  • 数据类型的&achar(*)[8]和的类型achar[8]简单地衰变成char*在大多数操作例如char* ptr = a;

    为了更好地理解阅读:区别char *strchar str[]记忆,如何既店?

第二种情况,

  • 声明char aa[8][8];创建一个8x8大小的二维数组.

  • 任何2-D阵列也可以被视为1-D阵列,其中每个阵列元素是1-D阵列.

  • aa是第一个元素的地址,是8个字符的数组.表达ptr2 = aa是有效和正确的.

  • 如果我们声明如下:

    char (*ptr3)[8][8];    
    char ptr3 = &aa;  //is a correct expression
    
    Run Code Online (Sandbox Code Playgroud)

    同样,
    moreThings在您的声明中char moreThings[8][8];包含第一个元素的地址,即8个元素的char数组.

    为了更好地理解阅读:区别char* str[]char str[][]记忆,如何既店?


知道这将是有趣的:

  • morething 是一个8字符数组的地址.

  • *morething是第一个元素的地址&morething[0][0].

  • &morething 是8 x 8的二维数组的地址.

    并且所有上述三个的地址值相同但在语义上都是不同的.

  • **morething是第一个元素的值morething[0][0].

    要理解更好的阅读:之间的区别,何时被宣布为?&strstrstrchar str[10]

更进一步,

  • void doThings(char thingsGoHere[8][8])只是空虚doThings(char (*thingsGoHere)[8]),因此接受任何二维数组,第二维为8.

关于C和C++中的变量类型:(我想在答案中添加)

  • 在C C++概念中,没有任何东西可以通过引用传递.如果它在C中使用,则表示作者在谈论指针变量.
  • C支持pass by Addresspass by value.
  • C++支持Pass by address,pass by value也是pass by Reference.

    读:指针变量和引用变量

在末尾,

  • 数组的名称是常量标识符不可变.


Who*_*ami 5

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);
}
Run Code Online (Sandbox Code Playgroud)

输出是:

.. 0x7fff6ae2ca5c  0x7fff6ae2cbec    = 400 bytes difference
.. 0x7fff6ae2ca5c  0x7fff6ae2ca84    = 40 bytes difference
 .. 0x7fff6ae2ca5c   0x7fff6ae2ca60  = 4 bytes difference. 
Run Code Online (Sandbox Code Playgroud)

&a +1 -> 通过添加整个数组大小来移动指针。即:400 字节

&a[0] + 1 -> 通过增加列的大小来移动指针。即:40 个字节。

&a[0][0] +1 -> 通过添加元素的大小来移动指针,即:4 个字节。

[整数大小为 4 个字节]

希望这可以帮助。:)