结构体的内存是怎么分配的?

3,240 阅读4分钟

每种数据类型所占的空间大小

首先我们来看一下各种数据类型所点的空间大小

结构体内存分配的原则

  • 1.数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第 一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要 从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组, 结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存 储。
  • 2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从 其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b 里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
  • 3.收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补⻬。

举几个例子进行说明

struct struct1{
    int a;   //a占四个字节,存在结构体的0-3位置,下一个位置是4
    float b; //b点四个字节,存在结构体的4-7的位置,下一个位置是8
    char c;  //c占一个字节,存在结构体的8的位置,下一个位置是9
    double d;//d占八点字节,由于9不是8的整数倍,所以开始存储的位置要后移到16的位置,其存在结构体的17-23的位置
}struct1;

struct1结构体所有元素所占的内存大小为24,24是结构体中所有元素中所占空间最大的元素d所占空间8的倍数,所以struct1所占的空间大小为24

struct1的内存分配情况如下图

从上图我们发现,9~15的位置没有存数据,有点浪费了

struct struct2{
    char a;//a占一个字节,存在结构体的0位置,下一个位置是1
    short b;//b占二个字节,1不是2的倍数,所以要后移到2,存在结构体的2-3位置,下一个位置是4
    double c;//c占八点字节,由于4不是8的整数倍,所以开始存储的位置要后移到8的位置,其存在结构体的8-15的位置,下一个位置是16
    int d;//d占一个字节,16是4是整数倍,存在结构体的16-19的位置
}struct2;

struct2结构体所有元素所占的内存大小为17,17不是结构体中所有元素中所占空间最大的元素c所占空间8的倍数,所以struct2所占的空间大小要增大到24

struct2的内存分配情况如下图

从上图我们发现,4~7的位置没有存数据,有点浪费了

struct struct12{
    double a;//a占八点字节,存在0-7的位置
    int b;//b占四个字节,存在8-11的位置
    short c;//c占二个字节,存在12-13的位置
    char d;//d占一个字节,存在结构体的14位置
}struct12;

struct12的内存分配情况如下图

从上图我们发现,只有15的位置没有使用到,只浪费了一个字节的内存。

我们知道,8是4的倍数,8和4是2的倍数,8、4和2是1的倍数;而数据类型的内存只有8、4、2和1四种,根据数据在结构体中存储的起始位置是数据类型所占内存的整数倍的原则我们可以发现,当结构体的元素按照所占内存倒序排列时,结构体所占的空间最少,也会被最有效的利用。所以我们在定义结构体时,应该尽量按这种规则来排列元素,以达到内存优化的目的。

struct struct3{
    char a;//a占一个字节,存在结构体的0位置,下一个位置是1
    short b;//b占二个字节,1不是2的倍数,所以要后移到2,存在结构体的2-3位置,下一个位置是4
    double c;//c占八点字节,由于4不是8的整数倍,所以开始存储的位置要后移到8的位置,其存在结构体的8-15的位置,下一个位置是16
    struct struct1 strut;//strut占24个字节,16是struct1点内存最大的元素d的内存8的整数倍,开始存储的位置为16,存在结构体的16-39
}struct3;

内存打印结果