数组的地址 – 具有&符号和没有&符号之间的区别

我有一个看起来像这样的结构:

struct packet { int a; char data[500]; }; typedef struct packet packet_t; 

我有点困惑为什么以下代码为每个printf输出相同的地址:

 void myfunction() { packet_t packet; printf("%p\n", packet.data); //eg, outputs 0x7fff1c323c9c printf("%p\n", &packet.data); //eg, outputs 0x7fff1c323c9c } 

有没有人对此有一个很好的解释?

我不知道为什么这会被拒绝,这是一个很好的问题,暴露了C的混乱行为。

之所以出现混乱,是因为通常在定义数组时会创建一个真正的指针:

 char data[100]; printf("%p\n", data); // print a pointer to the first element of data[] printf("%p\n", &data); // print a pointer to a pointer to the first element of data[] 

因此,在典型的32位桌面系统上,为data分配了4个字节,这是指向100个字符的指针。 Data ,指针,本身存在于内存中的某个位置。

在结构中创建数组时,不会分配指针。 相反,编译器会在运行时packet.data引用转换为指针,但不会分配任何内存来存储它。 相反,它只使用&packet + offsetof(data)

我个人更喜欢语法一致并需要一个&符号,packet.data会产生某种编译时错误。

在大多数情况下,类型为“N元素数组T ”的表达式将转换为“指向T指针”类型的表达式,其值将是数组中第一个元素的地址。 这是第一次printf调用中发生的事情; 表达式packet.data ,其类型为char [500] ,将替换为char *类型的表达式,其值为第一个元素的地址,因此您可以有效地打印&packet.data[0]

当数组表达式是一元&运算符的操作数时,会出现此规则的一个例外。 表达式&packet.data的类型是char (*)[500] (指向char 500元素数组的指针)。

数组的地址与第一个元素的地址相同,因此对printf两次调用都显示相同的 ; 只是表达式的类型不同。 要迂腐,两个表达式都应该在printf调用中转换为void *%p转换说明符需要一个void *参数):

 printf("%p\n", (void *) packet.data); printf("%p\n", (void *) &packet.data); 

那是因为数组衰减到指向序列中第一个元素的指针。 因此, packet.data地址位置与&packet.data&packet.data[0]

因为除了make和packet.data导致编译错误之外,这是唯一合理的事情。 整数a和数据字符数组按顺序排列在堆栈中,不涉及解除引用。