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

时间:2012-10-01 13:18:19

标签: c arrays pointers multidimensional-array callstack

我知道数组会衰减到指针,如果声明了

char things[8];

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

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

char moreThings[8][8];

然后moreThings 不是类型指向char的类型,但类型为“指向char的指针数组”,因为衰减只发生一次。

moreThings被传递给一个函数时(比如原型void doThings(char thingsGoHere[8][8]),堆栈实际上发生了什么?

如果moreThings不是指针类型,那么这仍然是一个传递参考吗?我想我一直认为moreThings仍然代表多维数组的基地址。如果doThings接受输入thingsGoHere并将其传递给另一个函数,该怎么办?

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

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

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

3 个答案:

答案 0 :(得分:22)

你有点错误: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 :(得分: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是一个有效的表达方式。

  • &a的数据类型为char(*)[8]a的类型为char[8],在大多数操作中只会衰减为char*,例如char* ptr = a; char aa[8][8];

    要理解更好的阅读:Difference between char *str and char str[] and how both stores in memory?

第二种情况,

  • 声明8x8会创建一个aa大小的二维数组。

  • 任何二维数组也可以视为一维数组,其中每个数组元素都是一维数组

  • ptr2 = aa是第一个元素的地址,它是一个包含8个字符的数组。表达式char (*ptr3)[8][8]; char ptr3 = &aa; //is a correct expression 有效且正确。

  • 如果我们声明如下:

    moreThings

    <强>类似地,
    声明char moreThings[8][8];中的morething包含第一个元素的地址,该元素是8个元素的char数组。

    要理解更好的阅读:Difference between char* str[] and char str[][] and how both stores in memory?


知道:

会很有趣
  • *morething是8个字符数组的地址。

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

  • **morething是8 x 8的二维数组的地址。

      

    以上三者的地址值相同但在语义上都不同。

  • morething[0][0]void doThings(char thingsGoHere[8][8])的第一个元素的值。

    要理解更好的阅读:Difference between &str and str, when str is declared as char str[10]?

此外,

  • doThings(char (*thingsGoHere)[8])只是空pass by Address,因此接受任何二维数组,第二维为8。

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

  • C 其C ++概念中没有任何内容可供参考。如果它在C中使用,则表示作者在谈论指针变量。
  • C支持pass by valuePass by address
  • C ++支持pass by valuepass by Reference以及{{1}}。

    阅读:pointer variables and reference variables

最后,

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

答案 2 :(得分:4)

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. 

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

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

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

[int size is 4 bytes]

希望这会有所帮助。 :)