数组名称是指针吗?

191 c arrays pointers

数组的名称是C中的指针吗?如果没有,数组的名称和指针变量之间有什么区别?

Tho*_*thy 235

数组是一个数组,指针是指针,但在大多数情况下,数组名称将转换为指针.经常使用的一个术语是它们会衰减到指针.

这是一个数组:

int a[7];
Run Code Online (Sandbox Code Playgroud)

a 包含七个整数的空间,你可以在其中一个中赋值赋值,如下所示:

a[3] = 9;
Run Code Online (Sandbox Code Playgroud)

这是一个指针:

int *p;
Run Code Online (Sandbox Code Playgroud)

p不包含任何整数空格,但它可以指向整数的空格.例如,我们可以将其设置为指向数组中的一个位置a,例如第一个:

p = &a[0];
Run Code Online (Sandbox Code Playgroud)

可能令人困惑的是你也可以这样写:

p = a;
Run Code Online (Sandbox Code Playgroud)

这并没有数组的内容复制a到指针p(无论这将意味着).相反,数组名称a将转换为指向其第一个元素的指针.因此,分配与前一个分配相同.

现在您可以p以类似的方式使用数组:

p[3] = 17;
Run Code Online (Sandbox Code Playgroud)

这有效的原因是C,中的数组解除引用运算符[ ]是根据指针定义的.x[y]意思是:从指针开始x,步骤y元素在指针指向的位置之后前进,然后取出那里的任何东西.使用指针算术语法,x[y]也可以写成*(x+y).

为了做到这与正常的阵列,比如我们的工作a,该名称aa[3]必须首先被转换为一个指针(在第一元件a).然后我们向前迈出3个元素,并采取任何在那里.换句话说:将元素放在数组中的第3位.(这是数组中的第四个元素,因为第一个元素编号为0.)

因此,总之,C程序中的数组名称(在大多数情况下)转换为指针.一个例外是我们sizeof在数组上使用运算符.如果a在此上下文中转换为指针,sizeof a则会给出指针的大小而不是实际数组的大小,这将是相当无用的,因此在这种情况下a意味着数组本身.

  • 数组名称不是指针.它是类型数组变量的标识符,它具有对元素类型指针的隐式转换. (31认同)
  • 另外,除了`sizeof()`之外,其他没有数组 - >指针衰减的上下文是运算符`&` - 在上面的例子中,`&a`将是一个指向7`int`数组的指针,而不是指向单个`int`的指针; 也就是说,它的类型是`int(*)[7]`,它不能隐式转换为`int*`.这样,函数实际上可以指向特定大小的数组,并通过类型系统强制执行限制. (26认同)
  • 类似的自动转换应用于函数指针 - "functionpointer()"和"(*functionpointer)()"意思相同,奇怪的是. (5认同)
  • 他没有询问数组和指针是否相同,但是如果数组的名称是指针 (3认同)
  • @ onmyway133,查看[here](http://c-faq.com/ptrs/funccall.html)进行简短说明和进一步引用. (3认同)
  • @Pavel:感谢关于&的评论.我知道还有其他例外,但sizeof是我心目中唯一的例外.我已经将"例外"改为"一个例外",我认为这表明还有其他例外(但我不是英语母语人士). (2认同)

pmg*_*pmg 33

当数组用作值时,其名称表示第一个元素的地址.
当数组未用作值时,其名称表示整个数组.

int arr[7];

/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */

/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
Run Code Online (Sandbox Code Playgroud)


Joh*_*ode 17

如果数组类型的表达式(例如数组名​​称)出现在更大的表达式中并且它不是&sizeof运算符的操作数,那么数组表达式的类型将从"N元素数组T"转换为"指向T的指针",表达式的值是数组中第一个元素的地址.

总之,数组名不是指针,但在多数情况下它被视为好像它是一个指针.

编辑

回答评论中的问题:

如果我使用sizeof,我是否只计算数组元素的大小?然后数组"head"也占用了有关长度和指针的信息的空间(这意味着它需要比普通指针更多的空间)?

创建数组时,唯一分配的空间是元素本身的空间; 没有存储实现单独的指针或任何元数据.特定

char a[10];
Run Code Online (Sandbox Code Playgroud)

你记忆中得到的是什么

   +---+
a: |   | a[0]
   +---+ 
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[9]
   +---+
Run Code Online (Sandbox Code Playgroud)

表达 a指的是整个阵列,但没有对象 a从数组元素本身分离.因此,sizeof a为您提供整个数组的大小(以字节为单位).表达式&a为您提供数组的地址,该地址与第一个元素的地址相同.&a和之间的差异&a[0]是结果1的类型- char (*)[10]在第一种情况下和char *在第二种情况下.

事情变得奇怪的是当你想要访问单个元素时 - 表达式a[i]被定义为*(a + i)- 给定地址值a,来自该地址的偏移i元素(不是字节)并取消引用结果.

问题是它a不是指针或地址 - 它是整个数组对象.因此,在C规则,无论何时编译器看到阵列类型的表达式(如a,已键入char [10])该表达式不是的操作数sizeof或一元&运算符,该表达式的类型被转换("衰变")到指针类型(char *),表达式的值是数组的第一个元素的地址.因此,表达式 a具有与表达式相同的类型和值&a[0](并且通过扩展,表达式*a具有与表达式相同的类型和值a[0]).

C由称为B更早的语言导出,B中a 从数组元素一个单独的指针对象a[0],a[1]等里奇想保持B的数组语义,但他不想惹存储单独的指针对象.所以他摆脱了它.相反,编译器将根据需要在转换期间将数组表达式转换为指针表达式.

请记住,我说数组不存储任何有关其大小的元数据.只要该数组表达式"衰减"到指针,您所拥有的就是指向单个元素的指针.该元素可以是元素序列中的第一个,也可以是单个对象.根据指针本身无法知道.

当你传递一个数组表达式的功能,所有功能接收到的是一个指向第一个元素-它不知道数组有多大(这就是为什么gets功能是这样的威胁,并最终从库中移除).要使函数知道数组有多少元素,必须使用sentinel值(例如C字符串中的0终止符),或者必须将元素数作为单独的参数传递.


  1. 哪*可能*影响地址值的解释 - 取决于机器.

  • @Stan:表达式“ a”的类型为“ int [2] [3]”,“衰变”类型为“ int(*)[3]”。表达式**(a + 1)的类型为int [3],它“衰减”为int *。因此,“ *(*(a + 1)+ 2)”将具有类型“ int”。a指向int的第一个3元素数组,a +1指向int的第二个3元素数组,**(a +1)*是第二个3元素的数组。 `int`数组,`*(a + 1)+ 2`指向第二个`int`数组的第三个元素,所以**(*(a + 1)+ 2)`***是第三个元素第二个int数组。如何将其映射到机器代码完全取决于编译器。 (2认同)

Gru*_*rig 5

一个像这样声明的数组

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

分配内存10 int秒.你不能修改,a但你可以用指针算术a.

像这样的指针只为指针分配内存p:

int *p;
Run Code Online (Sandbox Code Playgroud)

它没有分配任何ints.你可以修改它:

p = a;
Run Code Online (Sandbox Code Playgroud)

并使用数组下标,你可以使用:

p[2] = 5;
a[2] = 5;    // same
*(p+2) = 5;  // same effect
*(a+2) = 5;  // same effect
Run Code Online (Sandbox Code Playgroud)

  • 数组并不总是在堆栈上分配.Yhat的实现细节因编译器而异.在大多数情况下,静态或全局数组将从与堆栈不同的内存区域分配.可以从另一个存储区域分配const类型的数组 (2认同)