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


当前回答

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

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[]={1,2,3};
printf("%p\n",a);     //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0

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

0x7fff6fe40bc0

像这样声明的数组

int a[10];

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

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

int *p;

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

p = a;

并像使用a一样使用数组下标:

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

如果数组类型的表达式(例如数组名)出现在更大的表达式中,并且它不是&或sizeof操作符的操作数,则数组表达式的类型将从“T的n元素数组”转换为“指向T的指针”,并且表达式的值是数组中第一个元素的地址。

简而言之,数组名不是指针,但在大多数上下文中,它被视为指针。

Edit

在评论中回答这个问题:

如果我使用sizeof,我只计算数组元素的大小吗?然后数组“head”也占用了关于长度和指针的信息的空间(这意味着它占用了更多的空间,比一个正常的指针会)?

当你创建一个数组时,唯一分配的空间是元素本身的空间;没有为单独的指针或任何元数据具体化存储。鉴于

char a[10];

你在记忆中得到的是

   +---+
a: |   | a[0]
   +---+ 
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[9]
   +---+

表达式a指向整个数组,但是数组元素本身没有对象a。因此,sizeof a给出整个数组的大小(以字节为单位)。表达式&a给出了数组的地址,它与第一个元素的地址相同。&a和&a[0]之间的区别是result1的类型- char(*)[10]在第一种情况下,char *在第二种情况下。

奇怪的是,当你想访问单个元素时——表达式a[i]被定义为*(a + i)的结果——给定一个地址值a,从该地址偏移i个元素(不是字节)并解引用结果。

The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).

C语言源自早期的一种叫做B的语言,在B中a是一个独立于数组元素[0]、[1]等的指针对象。Ritchie想要保留B的数组语义,但他不想在存储单独的指针对象时搞得一团糟。所以他把它扔掉了。相反,编译器会在必要时将数组表达式转换为指针表达式。

记住,我说过数组不存储任何关于其大小的元数据。一旦数组表达式“衰减”为指针,您所拥有的就是一个指向单个元素的指针。该元素可以是元素序列的第一个,也可以是单个对象。根据指针本身是无法知道的。

当你将一个数组表达式传递给一个函数时,函数接收到的只是一个指向第一个元素的指针——它不知道数组有多大(这就是为什么gets函数如此危险,最终被从库中删除了)。为了让函数知道数组中有多少个元素,必须使用哨兵值(例如C字符串中的0结束符),或者必须将元素数量作为单独的参数传递。


这*可能*影响地址值的解释方式-取决于机器。

数组名本身会产生一个内存位置,所以你可以像对待指针一样对待数组名:

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]);

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

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