数组是指针吗?

新手上路,请多包涵

数组和指针在 C 和 C++ 中的实现方式不同吗?我遇到了这个问题,因为在这两种情况下,我们都从元素的起始地址访问元素。所以,它们之间应该有密切的关系。请解释它们之间的确切关系。谢谢。

原文由 yashu 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 955
2 个回答

让我们先把重要的东西弄清楚: 数组不是指针。数组类型和指针类型是 _完全不同的东西_,编译器的处理方式也不同。

产生混淆的地方在于 C 如何处理数组 _表达式_。 N1570

6.3.2.1 左值、数组和函数指示符

3 除非它是 sizeof 运算符、 _Alignof 运算符或一元 & 运算符的操作数,或者是用于初始化的字符串字面量,类型为 “array of type ” 的表达式被转换为类型为 “pointer to type ” 的表达式,它指向数组对象的初始元素,而不是左值。如果数组对象具有寄存器存储类,则行为未定义。

让我们看看以下声明:

 int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *parr = arr;

arrint 的 10 元素数组;它指的是一个足够大的连续内存块以存储 10 int 值。第二个声明中的 表达式 arr 是数组类型,但由于它不是 &sizeof 的操作数并且它不是字符串, 表达式 的类型变为“指向 int 的指针”,值为第一个元素的地址,或 &arr[0]

parr 是指向int的指针;它指的是一块大到足以容纳单个 int 对象的地址的内存块。如上所述,它被初始化为指向 arr 中的第一个元素。

这是一个假设的内存映射,显示了两者之间的关系(假设 16 位整数和 32 位地址):

对象地址 0x00 0x01 0x02 0x03
------ -------- ----------
   arr 0x10008000 0x00 0x00 0x00 0x01
                 0x10008004 0x00 0x02 0x00 0x03
                 0x10008008 0x00 0x04 0x00 0x05
                 0x1000800c 0x00 0x06 0x00 0x07
                 0x10008010 0x00 0x08 0x00 0x09
  帕尔 0x10008014 0x10 0x00 0x80 0x00

类型对于 sizeof&sizeof arr == 10 * sizeof (int) , which in this case is 20, whereas sizeof parr == sizeof (int *) , which in this case is 4. Similarly, the type of the expression &arr is int (*)[10] ,或指向 int 的类型是 &parr int ** 的指针,或指向 int 的指针 ---

请注意,表达式 arr&arr 将产生相同的 _值_( arr 中第一个元素的地址),但表达式的类型不同( int *int (*)[10] 分别)。这在使用指针算法时会有所不同。例如,给定:

 int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr;
int (*ap)[10] = &arr;

printf("before: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap);
p++;
ap++;
printf("after: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap);

“之前”行应该为所有三个表达式打印相同的值(在我们的假设地图中, 0x10008000 )。 The “after” line should show three different values: 0x10008000 , 0x10008002 (base plus sizeof (int) ), and 0x10008014 (base plus sizeof (int [10]) )。

现在让我们回到上面的第二段:在大多数情况下,数组 表达式 被转换为指针类型。我们来看下标表达式 arr[i] 。由于表达式 arr 没有作为 sizeof& 的操作数出现,并且由于它不是用于初始化另一个数组的字符串文字,类型从“ int ”的10元素数组转换为“指向 int 的指针”,并且正在对该 指针 值应用下标操作。实际上,当您查看 C 语言定义时,您会看到以下语言:

6.5.2.1 数组下标

2 后缀表达式后跟方括号 [] 中的表达式是数组对象元素的下标名称。下标运算符 [] 的定义是 E1[E2] 等同于 (*((E1)+(E2))) 。由于适用于二元 + 运算符的转换规则,如果 E1 是数组对象(等效地,指向数组对象的初始元素的指针)并且 E2 是整数,则 E1[E2] 指定第 E2 个元素 E1 (从零开始计数)。

实际上,这意味着您可以将下标运算符应用于指针对象 ,就好像 它是一个数组一样。这就是为什么代码喜欢

int foo(int *p, size_t size)
{
  int sum = 0;
  int i;
  for (i = 0; i < size; i++)
  {
    sum += p[i];
  }
  return sum;
}

int main(void)
{
  int arr[10] = {0,1,2,3,4,5,6,7,8,9};
  int result = foo(arr, sizeof arr / sizeof arr[0]);
  ...
}

以它的方式工作。 main is dealing with an array of int , whereas foo is dealing with a pointer to int , yet both are able to use the下标运算符 ,就好像 它们都在处理数组类型一样。

It also means array subscripting is commutative : assuming a is an array expression and i is an integer expression, a[i] and i[a] are both有效的表达式,并且两者都将产生相同的值。

原文由 John Bode 发布,翻译遵循 CC BY-SA 3.0 许可协议

不知道C++。对于 C, c-faq 的 答案比我以往任何时候都好。

来自 c-faq 的小片段:

6.3 那么C语言中的“指针和数组等价”是什么意思呢?

[…]

具体来说,等价的基石是这个关键定义:

对出现在表达式中的数组 T 类型对象的引用衰减(除了三个例外)成指向其第一个元素的指针;结果指针的类型是指向 T 的指针。

[…]

原文由 pmg 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题