14

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

char things[8];

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

另外,据我了解,如果有人声明

char moreThings[8][8];

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

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

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

规则是否差不多是除非指定一个数组输入,否则const该数组将始终是可修改的?

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

很抱歉,这个问题有点到处都是,但由于我难以理解这一点,因此很难表达出精确的询问。

4

3 回答 3

27

你弄错了: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

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

于 2012-10-01T13:24:35.093 回答
19

“数组地址和指向多维数组的指针”

让我们首先从一维数组开始:

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

  • char* ptr = a;ptr与指向 char 的指针 一样是正确的表达式,并且可以寻址第一个元素。

  • 但是表述ptr = &a错误的!因为ptr无法寻址数组。

  • &a 表示数组的地址。a和的真正值&a相同,但语义不同,一个是字符的地址,另一个是 8 个字符的数组的地址。

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

  • is的数据类型和&ais的char(*)[8]类型在大多数操作achar[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 数组。

    为了更好地理解阅读:两者之间的区别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])只不过是 void 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.

    阅读:指针变量和引用变量

在最后,

  • 数组的名称是常量标识符而不是变量。
于 2012-10-01T13:57:12.550 回答
5

克雷克很好地解释了,

除此之外,我们可以通过下面的例子来证明:

#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 个字节 ]

希望这可以帮助。:)

于 2012-10-01T13:57:22.960 回答