数组名是一个指针吗?

数组的名字是C中的一个指针吗? 如果不是,数组的名称和指针variables有什么区别?

一个数组是一个数组,一个指针是一个指针,但是在大多数情况下,数组名被转换为指针。 经常使用的一个术语是,他们衰变为指针。

这是一个数组:

 int a[7]; 

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

 a[3] = 9; 

这里是一个指针:

 int *p; 

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

 p = &a[0]; 

可以混淆的是,你也可以这样写:

 p = a; 

这不会将数组a的内容复制到指针p中 (无论这意味着什么)。 相反,数组名称a被转换为指向其第一个元素的指针。 所以这个任务和前一个一样。

现在你可以像使用数组一样使用p:

 p[3] = 17; 

这样做的原因是C中的数组解引用操作符“[]”是根据指针定义的。 x [y]的意思是:从指针x开始,在指针指向的地方向前走y个元素,然后取其中的任何东西。 使用指针算术语法, x [y]也可以写成*(x + y)

为了使用普通的数组,比如我们的a ,必须首先将a中的名字a转换为指针(a中的第一个元素)。 然后我们继续前进3个元素,并采取任何有。 换句话说:取数组中位置3的元素。 (这是数组中的第四个元素,因为第一个元素被编号为0)

所以,总而言之,C程序中的数组名(大多数情况下)转换为指针。 当我们在数组上使用sizeof运算符时,有一个例外。 如果a在这个上下文中被转换为一个指针,那么sizeof(a)就会给出一个指针的大小,而不是实际的数组,而这样做是无用的,所以在这种情况下, a意味着数组本身。

当数组用作值时,其名称代表第一个元素的地址。
当数组不被用作值时,它的名字代表整个数组。

 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 */ 

一个这样声明的数组

 int a[10]; 

为10个int分配内存。 你不能修改a但你可以用a指针算术。

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

 int *p; 

它不分配任何int 。 你可以修改它:

 p = a; 

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

 p[2] = 5; a[2] = 5; // same *(p+2) = 5; // same effect *(a+2) = 5; // same effect 

数组名称本身会产生一个内存位置,因此您可以将数组名称视为一个指针:

 int a[7]; a[0] = 1976; a[1] = 1984; printf("memory location of a: %p", a); printf("value at memory location %p is %d", a, *a); 

和其他漂亮的东西,你可以做指针(例如添加/减去偏移量),你也可以做一个数组:

 printf("value at memory location %p is %d", a + 1, *(a + 1)); 

在语言方面,如果C没有将数组暴露为某种“指针” (迂回地说它只是一个内存位置,它不能指向内存中的任意位置,也不能被程序员控制)。 我们总是需要编码:

 printf("value at memory location %p is %d", &a[1], a[1]); 

如果一个数组types的expression式(如数组名称)出现在一个较大的expression式中,并且它不是or或sizeof运算符的操作数,则数组expression式的types将从“T的N元素数组“到”指向T的指针“,expression式的值是数组中第一个元素的地址。

简而言之,数组名不是一个指针,但在大多数情况下,它被当作是一个指针。

我认为这个例子揭示了这个问题:

 #include <stdio.h> int main() { int a[3] = {9, 10, 11}; int **b = &a; printf("a == &a: %d\n", a == b); return 0; } 

它在gcc 4.9.2中编译得很好(有两个警告),并打印出下列内容:

 a == &a: 1 

oops 🙂

因此,结论是否定的,数组不是一个指针,它不是作为一个指针存储在内存中(甚至不是只读的),因为你可以用&运算符来获得它的地址。 但是 – 哎呀 – 那个操作员不行:-)),无论如何,你已经被警告过了:

 pc: In function 'main': pp.c:6:12: warning: initialization from incompatible pointer type int **b = &a; ^ pc:8:28: warning: comparison of distinct pointer types lacks a cast printf("a == &a: %d\n", a == b); 

C ++在编译时会拒绝任何这样的错误。

一个数组是内存中的一系列安全和连续的元素。 在C中,数组的名字是第一个元素的索引,应用偏移量可以访问其余的元素。 “第一个元素的索引”确实是指向内存方向的指针。

与指针variables的不同之处在于,你不能改变数组的名字所在的位置,所以它和const指针类似(它是相似的,不一样,见Mark的注释)。 而且,如果使用指针aritmetic,则不需要取消引用数组名称以获取值:

 char array = "hello wordl"; char* ptr = array; char c = array[2]; //array[2] holds the character 'l' char *c1 = ptr[2]; //ptr[2] holds a memory direction that holds the character 'l' 

所以答案有点“是”。

数组名称的行为像一个指针,并指向数组的第一个元素。 例:

 int a[]={1,2,3}; printf("%p\n",a); //result is similar to 0x7fff6fe40bc0 printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0 

这两个打印语句将为机器提供完全相同的输出。 在我的系统中,它给了:

 0x7fff6fe40bc0 

数组名称是数组第一个元素的地址。 所以是的数组名称是一个常量指针。

首先根据K&R,答案是肯定的。

在概念层面上,数组名是一个ptr,它们绝对是一样的东西,CONCEPTUALLY。

编译器如何实现一个数组取决于编译器。 这是说他们不是一回事的人和那些说他们的人之间的争论。

编译器可以实现int a[5]作为指向a可以包含5个整数的未命名存储块的指针。 但他们没有。 编译器编写器为一个简单的数组生成代码,然后在指针的指针上更容易。

无论如何,在概念上,由int a[5];分配的数据区域int a[5]; 语句可以由ptr a引用,也可以由&a[0]语句生成的指针引用。