malloc分配嵌套结构体时,其内层成员变量x是否存储在堆区?
结论
内层成员变量x确实存储在堆区,点运算符.和箭头运算符->的使用差异和成员所在的存储区域没有任何关联,底层也不存在特殊处理逻辑。
1. 结构体内存布局规则
C语言中结构体的非指针类型成员是直接内嵌在结构体的内存空间中的,不会单独开辟独立内存。当你通过malloc分配struct _three类型的内存时,整块内存都属于堆区,内嵌的所有层级结构体成员的存储空间都包含在这块内存里:
struct _one { int x; }; struct _two { struct _one one; }; struct _three { struct _two two; };
你定义的三个结构体都没有指针类型的成员,所以struct _three的总大小 = struct _two的大小 = struct _one的大小 = int类型的大小,x的地址和malloc返回的struct _three指针地址完全重合,自然属于堆区内存的一部分。
2. 两种成员访问运算符的本质区别
你对运算符的使用场景存在误解,这两种运算符的选择只和运算符左侧的操作数类型有关,和操作数对应的内存所在的存储区域(堆、栈、静态存储区)没有任何关系:
->运算符:左侧操作数必须是结构体指针类型,作用是先对指针解引用拿到结构体实体,再访问对应成员.运算符:左侧操作数必须是结构体实体类型,作用是直接访问当前结构体的对应成员
你写的three->two.one.x可以拆解为以下逻辑:
three是struct _three*类型的指针,所以用->访问其成员two,得到的two是struct _two类型的实体(不是指针)two是结构体实体,所以用.访问其成员one,得到的one是struct _one类型的实体one是结构体实体,所以用.访问其成员x
举个简单的反例就可以验证:如果在栈上定义struct _three stack_three;,访问x的写法是stack_three.two.one.x;如果把栈上结构体的地址赋值给指针struct _three *p = &stack_three;,访问x的写法就变成了p->two.one.x,和堆区结构体的访问写法完全一致,但此时x是存储在栈区的,足以证明运算符的选择和存储区域无关。
内容的提问来源于stack exchange,提问作者ADBeveridge
相关产品推荐
相关产品推荐

