首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C中,array,&array,&array[0]的地址怎么会一样?

在C中,array,&array,&array[0]的地址怎么会一样?
EN

Stack Overflow用户
提问于 2021-05-04 14:35:24
回答 3查看 128关注 0票数 0
代码语言:javascript
复制
int main(){
        long a[]={6,9,10};

        printf("%p\n",a);
        printf("%p\n",&a);
        printf("%p\n",&a[0]);

return 0;
}

结果是:

代码语言:javascript
复制
0x7ff9c94a10
0x7ff9c94a10
0x7ff9c94a10

这个结果真的让我很困惑!为什么它在相同的内存位置存储不同的值,在0x7ff9c94a10同时存在地址本身和值6

EN

回答 3

Stack Overflow用户

发布于 2021-05-04 21:07:02

一张图片应该会有帮助-我们假设64位long

代码语言:javascript
复制
             +––––––+
0x7ff9c94a10 | 0x06 | a[0]
             +––––––+
0x7ff9c94a18 | 0x09 | a[1]
             +–––—––+
0x7ff9c94a20 | 0x0a | a[2]
             +–––––—+

没有独立于数组元素本身的对象a,因此数组(&a,类型long (*)[3])的地址与其第一个元素(&a[0],类型long *)的地址相同。

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则“T的N元素数组”类型的表达式将被转换为“指向T的指针”类型的表达式,并且表达式的值是数组的第一个元素的地址,因此表达式a实际上与&a[0]相同,并且也具有类型long *

票数 1
EN

Stack Overflow用户

发布于 2021-05-04 17:41:26

正如K&R在“数组和指针”一章中所解释的那样,a (根据定义)是&a[0]的同义词。没有提到&a,但可以将其视为中间步骤。

您必须专注于标识符,这里是a。编译器所需要的只是a开始的地址和它的元素的类型。第二个元素必须是基址加上的一个元素大小。

&a&a[0]是要计算的表达式,而不是要存储的值。&a[23]也是计算出来的,而不是存储的:a+ 23 * elemsize。

代码语言:javascript
复制
    printf("%p\n",   a     );  

    printf("%p\n",   a+1   );  // address of next element, not byte  
    printf("%p\n", &(a[1]) );  // parens not needed

第2行和第3行在数组开始上方打印8字节(长大小)的地址。

位于0x7ff9c94a10的

存在于该地址本身

也许那个地址真的存在于同一地点。就像我们所有人一样。但是它有一个很长的"6“。

要用数组的地址填充数组,您可以执行以下操作:

代码语言:javascript
复制
    void *a[3];
    for (int i = 0; i < 3; i++)
        a[i] = &a[i];


    for (int i = 0; i < 3; i++) {
        printf("%p\n",  a[i]);
        printf("%p\n", &a[i]);
    }

打印:

代码语言:javascript
复制
0x7ffe0918cbe0
0x7ffe0918cbe0
0x7ffe0918cbe8
0x7ffe0918cbe8
0x7ffe0918cbf0
0x7ffe0918cbf0

存储地址/指针需要8个字节。longvoid *在这里有相同的大小。

printf("%p\n", a+i);也可以工作。不需要引用解除引用的元素:&a[i]

一个基本的数组和指针规则是E1[E2] is *(E1 + E2)。E1必须指定一个数组,而E2和integer,因此

代码语言:javascript
复制
a[i]
*(a + i)

都是一样的。按原样

代码语言:javascript
复制
&(a[i])
&a[i]
a + 1

数组从定义的地址开始的想法很简单。但是谈论it...natural语言可以有双重含义:

代码语言:javascript
复制
"Have you seen number 12 today?" (the guest)

"Did you clean number 12?" (not the guest, the room)

障碍物

不知何故。但是在void **b = a;之后,你可以像a一样使用指针b (只是它有自己的新&b),a = ...是不可能的(赋值给裸数组)。

新示例

您的long类型非常适合存储指向某个对象的指针,但它使上面的示例变得复杂。这里是一个简单的int数组,所以没有人会想要存储地址。它显示了一个数组和一个指针共享什么和不共享什么:

代码语言:javascript
复制
int main(){
        int a[3] = {10,20,30};

        int *b;
        b = a;

        for (int i = 0; i < 3; i++) {
            printf("%p\n",  &a[i]);
            printf("%p\n",  &b[i]);
            printf("%p %d\n",   a+i, a[i]);
            printf("%p %d\n",   b+i, b[i]);
        }
        printf("%p\n",        a);
        printf("%p b = a\n",  b);
        printf("%p\n",                          &a);
        printf("%p <-- different, &b != &a\n",  &b);

return 0;
}

这提供了:

代码语言:javascript
复制
0x7fff72f0ed8c
0x7fff72f0ed8c
0x7fff72f0ed8c 10
0x7fff72f0ed8c 10
0x7fff72f0ed90
0x7fff72f0ed90
0x7fff72f0ed90 20
0x7fff72f0ed90 20
0x7fff72f0ed94
0x7fff72f0ed94
0x7fff72f0ed94 30
0x7fff72f0ed94 30
0x7fff72f0ed8c
0x7fff72f0ed8c b = a   (same as top index zero)
0x7fff72f0ed8c
0x7fff72f0ed80 <-- different, &b != &a

差异(12个字节,"0“代表"c")并不显著,但这并不重要。除了数组元素之外,b还有生命周期,而a则没有。

随之而来的是,指针b可以被赋值(就像b = a一样),但是数组a不能。

怎么会这样呢?

阵列、&阵列、&阵列的地址

这实际上是非常不清楚的。array的地址是&array (不知何故),但&array的地址既不是&&array (关于标签‘&array’的错误)也不是&(&array) (错误:需要左值)。

票数 0
EN

Stack Overflow用户

发布于 2021-05-07 00:04:55

井,

代码语言:javascript
复制
array

根据定义,是第一个元素的地址,这等同于:

代码语言:javascript
复制
&array[0]

这就解释了为什么两者都有相同的地址。

第二个表达式是数组的地址。通常,(我现在不记得这是不是由标准强制执行的)数组是通过一个接一个的元素存储的,从第一个元素开始……因此,数组地址与第一个元素的地址相同是正常的。但是,如果您检查指向对象的类型,您将看到这些表达式之间的差异:

代码语言:javascript
复制
*array

是数组的元素的类型,而

代码语言:javascript
复制
*&array

是整个数组类型。

所以,让我们假设你有

代码语言:javascript
复制
char array[10];

然后

代码语言:javascript
复制
array

的类型

代码语言:javascript
复制
char *

代码语言:javascript
复制
*array

类型为char,而

代码语言:javascript
复制
&array

的类型为10个字符的数组,或者

代码语言:javascript
复制
char [10]

如何验证这一点?只需运行以下程序:

代码语言:javascript
复制
#include <stdio.h>

/* print the expression and it's size */
#define P(T) printf("sizeof("#T") == %zu\n", sizeof(T))

int main()
{
    char array[10];

    P(   array    );
    P(  *array    );
    P(  &array    );
    P( *&array    );
    P(   array[0] );
    P(  &array[0] );
    P( *&array[0] );
}

当(在我的系统上)运行时,它会产生:

代码语言:javascript
复制
$ a.out
sizeof(array) == 10         <-- the size of the array
sizeof(*array) == 1         <-- the size of the pointed to first element (as by def)
sizeof(&array) == 8         <-- size of a pointer to the array.
sizeof(*&array) == 10       <-- size of the pointed to object (the array)
sizeof(array[0]) == 1       <-- size of the first element.
sizeof(&array[0]) == 8      <-- size of a pointer to the first element (as above)
sizeof(*&array[0]) == 1     <-- size of the pointed to first element.
$ _

(右边的文字是对数字的解释)

关于&&的错误的原因(这属于给出的答案之一,由于某种原因,已经将&链接到它的两个应用程序中,并得到了关于标签运算符的错误)是,对于语言的GCC扩展,GCC有一个一元运算符&&。在C中没有&&一元运算符,如果你继续使用-pedantic,你会得到一个错误,当你尝试使用不带左操作数的逻辑与运算符(&&)时,会出现语法错误。无论如何,如果您尝试像下面这样分隔操作数

代码语言:javascript
复制
& & array

然后你会得到另一个错误,因为子表达式&array没有表示左值(在内存中没有表示),因此不能应用&左一元运算符(你不能获得值的地址)。

你的最后一段很有趣:你说

这个结果真的让我很困惑!为什么它在相同的内存位置存储不同的值,在0x7ff9c94a10同时存在地址本身和值6

它们并不是不同的价值观。这里的问题是,三个不同的表达式中的两个表示不同的东西,但在相同的位置,因为数组在内存中从与其第一个元素相同的点开始。

你在家里的时候,你和你的房子有相同的邮寄地址,但是你和你的房子是不一样的,对不对?这就是这里正在发生的事情:&array (是您的房子的地址,数组)和&array[0] (是您的地址,它与房子的邮寄地址相同,因为您在房子里)。问题是你有三个表达式,你不知道表达式array的意思是,通过它的定义,字面上是指向第一个元素的指针,这使得它等同于&array[0] (类似于缩写)。因此,我们结束了三个具有相同值的表达式,其中两个是相同的东西(确切地说),另一个表示不同的东西。可能在你读完这一段之后,你需要再读一遍上面这个简单程序的输出,然后你就会发现不同之处在哪里(显然,你的房子比你大)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67379858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档