C语言中取结构体数组成员地址的&(p_t->x)表达式是否合法?
关于C语言中&(p_t->x)表达式合法性的解析
先看测试代码:
struct test { int x[3]; }; int main() { struct test t; t.x[0] = 1; t.x[1] = 2; t.x[2] = 3; struct test *p_t; p_t = &t; printf("p_t->x: %p\n", p_t->x); printf("&(p_t->x[0]): %p\n", &(p_t->x[0])); printf("&(p_t->x): %p\n", &(p_t->x)); return 0; }
运行输出:
p_t->x: 0x7ffe49dd2abc &(p_t->x[0]): 0x7ffe49dd2abc &(p_t->x): 0x7ffe49dd2abc
核心疑问:&(p_t->x)是否合法?是否属于未定义行为?
答案是:这个表达式完全合法,不属于未定义行为,只是它的类型和常规写法有差异,地址数值相同是C语言数组内存布局特性导致的结果。
详细解析三种表达式的区别
p_t->x:访问结构体数组成员时,数组名会自动退化为指向首元素的指针,类型是int *,指向t.x[0]的内存地址。&(p_t->x[0]):直接取数组第一个元素的地址,类型也是int *,和上面的表达式指向同一个内存位置。&(p_t->x):这里的p_t->x是完整的数组类型(int[3]),取数组本身的地址,得到的是指向数组的指针,类型为int (*)[3]。
为什么地址数值相同?
在内存中,数组的起始地址就是其首元素的起始地址,所以三者打印出来的地址值完全一致,但类型差异会影响后续指针运算:
- 对
int *类型指针执行+1,会偏移一个int的长度(通常4字节); - 对
int (*)[3]类型指针执行+1,会偏移整个数组的长度(通常12字节)。
结论
如果代码目标是获取数组首元素的指针,&(p_t->x)虽然地址值正确,但类型不符合预期,属于不规范写法。推荐使用p_t->x或&p_t->x[0],这两种写法更直观,也契合代码的实际意图。
内容的提问来源于stack exchange,提问作者aapje06
相关产品推荐
相关产品推荐

