打印
[应用相关]

结构体和指针

[复制链接]
99|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
szt1993|  楼主 | 2025-2-22 23:04 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

结构体内包含多个成员,这些成员之间在内存中是如何存放的呢?

比如:


<p>struct fraction {</p><p> int num; // 整数部分</p><p> int denom; // 小数部分</p><p>};</p><p>
</p><p>struct fraction fp;</p><p>fp.num = 10;</p><p>fp.denom = 2;</p>

这是一个定点小数结构体,它在内存占 8 个字节(这里不考虑内存对齐),两个成员域是这样存储的:


我们把 10 放在了结构体中基地址偏移为 0 的域,2 放在了偏移为 4 的域。

接下来我们做一个这样的操作:

<p>((fraction*)(&fp.denom))->num = 5; </p><p>((fraction*)(&fp.denom))->denom = 12; </p><p>printf("%d\n", fp.denom); // 输出多少?</p>

上面这个究竟会输出多少呢?自己先思考下噢~

接下来我分析下这个过程发生了什么:


首先,&fp.denom表示取结构体 fp 中 denom 域的首地址,然后以这个地址为起始地址取 8 个字节,并且将它们看做一个 fraction 结构体。

在这个新结构体中,最上面四个字节变成了 denom 域,而 fp 的 denom 域相当于新结构体的 num 域。

使用特权

评论回复
沙发
szt1993|  楼主 | 2025-2-22 23:05 | 只看该作者
因此:

((fraction*)(&fp.denom))->num = 5

实际上改变的是 fp.denom,而

((fraction*)(&fp.denom))->denom = 12

则是将最上面四个字节赋值为 12。

当然,往那四字节内存写入值,结果是无法预测的,可能会造成程序崩溃,因为也许那里恰好存储着函数调用栈帧的关键信息,也可能那里没有写入权限。

大家初学 C 语言的很多 coredump 错误都是类似原因造成的。

所以最后输出的是 5。

为什么要讲这种看起来莫名其妙的代码?

就是为了说明结构体的本质其实就是一堆的变量打包放在一起,而访问结构体中的域,就是通过结构体的起始地址,也叫基地址,然后加上域的偏移。

其实,C++、Java 中的对象也是这样存储的,无非是他们为了实现某些面向对象的特性,会在数据成员以外,添加一些 Head 信息,比如C++ 的虚函数表。

实际上,我们是完全可以用 C 语言去模仿的。

这就是为什么一直说 C 语言是基础,你真正懂了 C 指针和内存,对于其它语言你也会很快的理解其对象模型以及内存布局。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

300

主题

2425

帖子

6

粉丝