数组是指针?

yas*_*shu 17 c c++ arrays pointers

可能重复:
数组名是C中的指针吗?

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

Joh*_*ode 52

让我们首先得到重要的东西:数组不是指针.数组类型和指针类型是完全不同的东西,编译器会对它们进行不同的处理.

出现混淆的地方是C如何处理数组表达式.N1570:

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

...
3除了当它是的操作数sizeof运算符,_Alignof操作者,或一元&运算符,或者是用于初始化数组文本的字符串,其具有输入""的阵列的表达类型 ""被转换为表达式用类型""指针键入指向阵列对象的初始元素,不是左值"".如果数组对象具有寄存器存储类,则行为未定义.

我们来看看以下声明:

int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *parr = arr;
Run Code Online (Sandbox Code Playgroud)

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

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

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

Object           Address         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
  parr           0x10008014      0x10  0x00  0x80  0x00

这些类型对于像sizeof和的事物很重要&; sizeof arr == 10 * sizeof (int)在这种情况下,它是20,而sizeof parr == sizeof (int *)在这种情况下,它是4.类似地,表达式的类型&arrint (*)[10],或指向10元素数组的指针int,而&parris 的类型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);
Run Code Online (Sandbox Code Playgroud)

"之前"行应该为所有三个表达式打印相同的值(在我们的假设图中0x10008000)."本经"行应该表现出三个不同的值:0x10008000, 0x10008002(基地+ sizeof (int))和0x10008014(基地+ sizeof (int [10])).

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

6.5.2.1数组下标
...
2后缀表达式后跟方括号[]中的表达式是数组对象元素的下标名称.下标运算符[]的定义是E1 [E2](*((E1)+(E2)))相同.由于适用于binary +运算符的转换规则,如果E1是数组对象(等效地,指向数组对象的初始元素的指针)并且E2是整数,则E1 [E2]指定E2的2个元素.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]);
  ...
}
Run Code Online (Sandbox Code Playgroud)

它的工作方式. main正在处理一个数组int,而foo正在处理一个指针int,但两个都能够使用下标运算符,就好像它们都处理数组类型一样.

它还意味着数组下标是可交换的:假设a是一个数组表达式并且i是一个整数表达式,a[i]并且i[a]都是有效的表达式,并且两者都将产生相同的值.

  • @baruch:主要是为了使示例内存映射合理的大小.因为我老了. (4认同)
  • +1尤其适用于`arr`和`&arr` (2认同)
  • 只是好奇,为什么你使用了一个假设的例子`sizeof(int)== 2`,虽然标准允许,但在任何主流平台/编译器中都没有出现过? (2认同)

pmg*_*pmg 20

不了解C++.对于C来说,c-faq的答案要比以往任何时候都好得多.

来自c-faq的小片段:

6.3那么C中"指针和数组的等价"是什么意思?

[...]

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

对表达式中出现的array-of-T类型的对象的引用将(有三个例外)衰减为指向其第一个元素的指针; 结果指针的类型是指向T的指针.

[...]


Kir*_*sky 7

在C++中根据C++标准4.2:

可以将"N T数组"或"T的未知数组的数组"类型的左值或右值转换为"指向T的指针"的右值.结果是指向数组的第一个元素的指针.


Ben*_*igt 6

不,它们的实现方式不同.两者都找到具有相同计算的元素:a[i]是地址a + i*sizeof(a[0]),也是p[i]地址p + i*sizeof(p[0]).

但是,类型系统对它们的处理方式不同.C++在数组上有输入信息,可以通过sizeof operator(如C),模板推理,函数重载,RTTI等看到.基本上语言中使用类型信息的任何地方,指针和数组都可能表现不同.

C++中有许多例子,其中两种不同的语言概念具有相同的实现.只是几个:数组与指针,指针与引用,虚函数与函数指针,迭代器与指针,for循环与while循环,异常vs longjmp

在每种情况下,都有不同的语法和不同的思考方式,但最终会产生相同的机器代码.


Arm*_*yan 5

在C++中(我认为在C中),数组不是指针,可以通过以下方式证明.

#include <iostream>
int main()
{
   char arr[1000];
   std::cout << sizeof arr;
}
Run Code Online (Sandbox Code Playgroud)

如果arr是一个指针,这个程序将打印sizeof(char*),通常为4.但它打印1000.

另一个证据:

template <class T>
void f(T& obj)
{
   T x = obj; //this will fail to compile if T is an array type
}

int main()
{
   int a[30] = {};
   int* p = 0; 
   f(p); //OK
   f(a); //results in compile error. Remember f takes by ref therefore needs lvalue and no conversion applies
}
Run Code Online (Sandbox Code Playgroud)

形式上,一个数组被转换为指向lvalue-to-rvalue转换中第一个元素的指针,也就是说,当一个rvalue被预期时,在一个上下文中给出一个数组类型的左值,该数组被转换为指向它的第一个元件.

此外,声明为按值获取数组的函数等同于获取指针的函数,即

void f(int a[]);
void f(int a[10]);
void f(int* a);
Run Code Online (Sandbox Code Playgroud)

是三个等同的声明.HTH