C语言 数组的地址-有与无的区别

krcsximq  于 2023-02-03  发布在  其他
关注(0)|答案(6)|浏览(141)

我有一个如下所示的结构体:

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

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

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

对此,有谁能给出一个好的解释?

iqjalb3h

iqjalb3h1#

在大多数情况下,一个类型为“T的N元素数组“的表达式将被转换为类型为“指向T的指针“的表达式,其值将是数组中第一个元素的地址。这是在第一次printf调用中发生的事情;类型为char [500]的表达式packet.data被替换为类型为char *的表达式,其值为第一个元素的地址,因此实际上打印的是&packet.data[0]
当数组表达式是一元&运算符的操作数时,此规则有一个例外;表达式&packet.data的类型是char (*)[500](指向char的500元素数组的指针)。
数组的地址与第一个元素的地址相同,因此对printf的两次调用显示相同的 value;只是表达式的类型不同,为了学究气,两个表达式都应该在printf调用中强制转换为void *%p转换说明符需要一个void *参数):

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

ccgok5k52#

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

qoefvg9y

qoefvg9y3#

根据C11(6.3.2.1.3)节,当数组用作sizeof和一元&运算符的操作数时,数组衰减为指向其第一个元素 除外)的指针。
因此,packet.data * 不会 * 在表达式&packet.data中衰减为&packet.data[0],结果将是char (*)[500]类型的指针,并且在数值上与其第一个元素packet.data[0]的地址相同。

dgsult0t

dgsult0t4#

虽然现有的答案在技术上已经是正确的,而且还包括相关的C ISO标准部分,但我觉得它根本没有说明为什么这些问题重要。
既然问题是关于"差异",我将尝试提供一个实际的差异。
考虑:
编译并运行:

$ gcc array.c -o array && ./array
array.c: In function 'main':
array.c:11:5: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
   p = &s;
     ^
0x7f7ffff0622e 0x7f7ffff0622e 0x7f7ffff0622e
0x7f7ffff0622f 0x7f7ffff0622f 0x7f7ffff06238

这里有两点需要注意:
1.编译器会对不兼容的指针类型发出一个错误(已经在其他答案中解释过了)。所以这样一来,它们不仅在学术上不同,而且在实际上也不同(类型方面)。

  1. (char *)(char (*)[10])的指针算法是不同的。在第一行printf中,我们可以看到所有不同的变量都指向同一个地址。* 然而 *,在执行指针算法时,它们的值会出现偏差。在(char *)的情况下,指针算法按预期工作。变量加1将使地址增加1。对于(char (*)[10]),变量加1将使地址增加10。
clj7thdc

clj7thdc5#

因为这是除了使&packet.data导致编译错误之外唯一合理的做法,Integer a和data char数组在堆栈中是按顺序排列的,不涉及解引用。

pkmbmrz7

pkmbmrz76#

我不知道为什么这个问题被否决了,这是一个很好的问题,它暴露了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个字节,data是指向100个字符的指针。Data,指针本身存在于内存中的某个地方。
当你在一个结构体中创建一个数组时,并没有分配指针。相反,编译器在运行时将对packet.data的引用转换成一个指针,但不分配任何内存来存储它。相反,它只使用&packet + offsetof(data)
就我个人而言,我更希望语法保持一致,并且需要一个“与”符号,因为packet.data会生成某种编译时错误。

相关问题