如何获取数组指针的地址?

How to get the address of an array pointer?

我有以下c代码:

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
int **pp = &arr;

编译器报错,我不知道为什么。 arr 不是指向 int 数组的指针吗?我应该能够将它的地址分配给一个 int**。 还有其他方法吗?

Isn't arr a pointer points to an int array?

不,arr 根本不是指针。 arr 是一个数组。如果你取arr的地址,你得到的是一个指向数组的指针,而不是一个指向指针的指针。这会起作用:

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
int (*pp)[8] = &arr;

// cleaner by using a type alias:
using Arr8 = int[8];
Arr8* pp = &arr;

如果你想要一个指向指针的指针,那么你必须首先创建一个你可以指向的指针:

int*  p  = arr; // same as = &arr[0]
int** pp = &p;

But when I do printf("arr: %x\n", arr);. It actually prints out the starting address of arr. Doesn't that mean it is a variable stores the address of the array?

不是这个意思。 arr是数组;它不存储数组的地址,变量的类型不是指针。

当您将数组作为可变参数传递时,它将隐式转换为指向第一个元素的指针。这与上面示例中发生的隐式转换相同:int* p = arr;.

请注意,%x 格式说明符要求参数的类型为 int(或类似)。 int*(隐式转换的结果类型)是错误的类型,因此程序的行为将是未定义的。

如果你有一个像

这样声明的对象
T x;

其中 T 是某种类型说明符,那么指向此类对象的指针声明将类似于

T *p = &x;

现在考虑数组

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};

使用此类型 def

typedef int T[8]:

你可以像这样重写数组声明

T arr = {1, 2, 3, 4, 5, 6, 7, 8};

所以指向对象 arr 的指针声明看起来像

T *p = &arr;

由于类型说明符 T 表示类型 int[8],因此指向该类型对象的指针将具有类型 int ( * )[8].

所以上面的声明看起来像

int ( *p )[8] = &arr;

至于声明

int **pp;

那么可以通过以下方式引入

int *p = arr;
int **pp = &p;

那是在第一个声明中

int *p = arr;

数组指示符 arr 被隐式转换为指向其第一个元素的指针。所以指针p是由数组第一个元素的地址arr.

初始化的

反过来指针pp由指针p的地址初始化。

array name 本身就是 [0] index 的地址所以只需要像这样制作一个指针 int *p=array_name; 现在只需增加指针并访问数组,就像这样。 *(array_name + i) 其中 i 可以是您要访问的任何索引。

数组和指针是根本不同的东西:

  • 将数组想象成一条有建筑物的街道:每栋建筑物都有一个编号,街道有一个名称。在定义中 int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 数组名称 arr 就像街道名称,编号为 07 的数组元素是包含每个数字的建筑物。

  • 指针是一个包含对象地址的对象:一张写有建筑物地址的纸:char *p = &arr[1]; 类似于在纸上写 1, street arr一张纸。为方便起见,但更容易混淆,char *p = arr; 等同于 char *p = &arr[0]; 就像告诉你的 GPS 去第五街会带你到那条街上的第一所房子。

  • 一个指针指向一个指针,int **pp是一张纸上写地方的地方,另一张纸上写着上面那段楼的地址。在某些情况下可能需要这种类型的指针,但不像常规指针那样常见。

  • 定义int **pp = &arr;不正确,因为&arr不是指针的地址。它是完整数组的地址arr,是一种特殊类型的指针,就像契约是一种描述实际属性的特殊类型的文件:街道的完整延伸arr,包括人行道、人行道、地块和在其上竖立的建筑物。 指向完整数组的指针具有特殊语法:int (*p)[8] = &arr; 它仅用于高级 C 编程。大多数程序员永远不需要,甚至可能不理解语法,就像在现实生活中一样,属性 行为很少在律师办公室和官方场所之外看到,而且对 民众来说大多是深奥的.

  • 为了您的目的,您可以定义一个指向 int 的指针并使其指向数组的开头: int *p = arr; 如果您真的需要一个指向指向 int 的指针,您可以将 pp 定义为 int **pp = &p;

  • 通过pp访问数组的第3个元素将写成(*pp)[3]pp[0][3]1.


1 以及其他可读性较差的可能性:*(*pp + 3)*(3 + *pp) 和完全晦涩的替代方案:3[*pp]3[0[pp]]。 ..

案例一

这里我们考虑语句:

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};

以上语句创建了一个名为 arr 的数组,大小为 8,包含 int 个元素。数组 arr 的类型是 int [8].

案例二

这里我们考虑语句:

int **pp = &arr;

以上声明需要注意以下几点:

  1. 在左侧,我们有一个 指向名为 ppint 的指针。也就是说,左边pp的类型是int**.
  2. 在右边,我们有表达式&arr。由于从案例1,我们知道数组arr的类型是int [8]。因此,&arrint (*)[8],它被读作 指向大小为 8 且元素类型为 int.
  3. 的数组的指针

所以基本上,左侧的类型是 int**(来自第 1 点),而右侧的类型是 int (*)[8](来自第 2 点)。也就是说,左边和右边的类型不匹配。这就是编译器给我们错误提示的原因:

error: cannot convert ‘int (*)[8]’ to ‘int**’ in initialization

这意味着您正在尝试初始化 pp,它是一个 int**,类型为 int (*)[8].[=37 的 initializer =]

解决这个你需要确保左右手边的类型匹配,如下所示:

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
int (*pp)[8] = &arr; //now the type on rhs and lhs match

现在左侧 pp 的类型是 int (*)[8] ,它与右侧 &arr 的类型匹配,因此这个程序工作正常。