1. struct number_2
    {
        char a;
        int b;
        double c;
    }st2;
    //第一个成员a 内存起始位置从0 开始
    // b 占4个字节,他的起始位置必须是 4 的非负整数倍,所以这里从4开始  (内存对齐原则)
    // c 占8个字节,他的起始位置必须是 8 的非负整数倍,所以这里从8开始

  2. struct number_4
    {
        char a;
        int b;
        char c;
    }st4;
    // a 还是从0 开始
    // b 占4个字节,要从4的非负整数倍 开始,这里就是从 4开始
    // c 占1个字节,但是前面占内存最大的并不是1个字节的,所以采取 内存补齐原则 , 他就必须按照前面已有的占内存最大的成员的方式进行分配空间
  3. struct $
        {
            int a;
            char b;
            short c;    
        };
    // 占8 个字节
    // 内存对齐,b 占用一个字节,补齐4个字节,实际上空出了 3个字节,而c 占两个字节,可以用b 空闲出来的内存 保存c 的值,但是要注意c 的起始位置不是5,而是6。b 和 c 加在一起的内存没有超过这里最大的int 4个字节内存 

     总结(按我自己的理解):结构体中每个成员分配内存空间是按照声明的顺序(从前到后依次分配),正在分配内存空间的当前成员我们称之为a,a的内存起始位置一定是a自身所需内存的非负整数倍(假设a 是 short 类型占2字节,那就是2的非负整数倍,a 是int 类型,那就是4的非负整数倍),如果a是它之前声明的成员中所需内存最大的,那么分配的内存长度就是a自身那么大(a是int ,就分配4字节),否则就要按之前的最大的成员的内存来分配(比如之前有double,那分配的内存就是8字节)。还要注意有连续的情况,比如在int 类型后面有三个char 类型,这个时候同样按照之前方法计算,有一点要知道空闲出来的内存是可以被利用的,这个空闲的内存被利用的条件是同样符合内存对齐原则,下面代码举个例子。总之,就是你能计算出要分配内存的成员的起始位置和应该分配给它的内存长度并且要知道什么情况空闲出来的内存可以利用,什么情况下不可以利用。

    struct example
    {
        int a;  // 起始位置 0
        char b; // 起始位置 4
        short c; // 起始位置 6 而不是5,short占2字节要内存对齐
        char d;  // 起始位置 8
    }
    // 这个b 起始位置是从4 开始,空闲出来3个字节内存,c 占两个字节内存空间,可以被c 利用起来,不过c 的起始位置要从2的整数倍开始,就得从6开始了,而不是5.所以 b 和 c 之间有空出来了一个字节的内存空间。所以d 就利用不上那个空闲的内存了,
    // 如果 c 和 d 位置互换,那么刚好空闲的内存全部利用上。

     

     

  4. 来自:https://blog.csdn.net/Apollon_krj/article/details/51302859 (详细内容参考该连接)
  5. 为何需要内存对齐?
    不严谨的简单解释是这样的,你的CPU和总线是64位的,所以CPU每次可以从内存里面拿出8个字节,而这8个字节是对齐的,也就是说只能是0-7,8-15, 16-23这样的,不能从中间拿。这个时候你要读一个double,如果double的地址可以被8整除,那你就只需要跟内存要一次数据。如果不能整除,那你就得跟内存要2次数据。
    参考:  https://www.zhihu.com/question/27862634/answer/1136649507