数组名是一个指针吗?
数组的名字是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]
语句生成的指针引用。