C语言基础(七)结构体对齐与指针进阶

结构体对齐

成员偏移的计算方法

成员偏移(member offset):相对于结构体首地址的偏移

结构体对齐支持1 2 4 8 16 项目属性中代码生成可设置

MSVC编译器默认对齐是8 属性 /Zp8
member offset % min(ZpValue,sizeof(member type)) == 0
成员的偏移取模  取默认对齐的值与偏移后的成员的类型大小的最小值

#include<stdio.h>
#include<malloc.h>
typedef struct _Info
{
    char szValue[6];
    相对于结构体首地址偏移0 
    float fValue;
    相对于结构体首地址偏移8 offset % min(8,4) 相当于 offset % 8 == 0
    offset的值为8
    不能是4的原因:offset是相对于首地址偏移。char占了6位,所以再占内存从第7位开始占。配合公式取第一个可取的数就是8
    此时char所占六个字节但要偏移八个字节,未占的字节被填充
    double dbValue;
    相对于结构体首地址偏移16 offset % min(8,8) 相当于 offset % 8 == 0
    offset的值为16
    16的原因:float占内存从地址9(内存开始的地址)+ 4(自己要占内存的大小)= 13(到float占完内存后的新位置),所以offset从13位开始套公式计算,最终结果是16
    short sValue;
    相对于结构体首地址偏移24 offset % min(8,2) 相当于 offset % 2 == 0
    offset的值为24
    int nValue;
    相对于结构体首地址偏移26 offset % min(8,4) 相当于 offset % 4 == 0
    offset的值为28
    char cValue; 
    相对于结构体首地址偏移32 offset % min(8,4) 相当于 offset % 1 == 0
    //offset的值为32
}Info,*pInfo;//结构体定义完以后相对于结构体首地址偏移33
int main()
 {
    Info obj = { "rkvir", 12.5f,100.5,222,0xFFFFFFF,'c' };
    上述结构体内存如下
    72 6b 76 69 rkvi
    72 00 cc cc r\0aa
    00 00 48 41 float
    cc cc cc cc 
    00 00 00 00 double
    00 20 59 40 double
    de 00 cc cc short
    ff ff ff ff int
    63 char
    一共33字节
    printf("%d\r\n", sizeof(Info));
    sizeof(Info) = 40  
    变量总和 6 + 4 + 8 + 2 + 4 + 1 = 25
    最大对其 * 成员个数 = 48
    成员对齐后大小 = 33
    对齐支持1 2 4 8 16 项目属性中代码生成可设置
    size % 8 == 0 从33开始取
    sizeof(Info)== 40

所以最终结构体大小为40

结构体中指针的应用


    pInfo pobj;
    pobj = &obj;
    printf("0x%X\r\n",*(int*)((char*)pobj + 28));
    //pobj指向结构体首地址 + 28指向成员
    //加的28是指针定义的是什么类型,加的长度就是什么类型的长度
    //由于是28个字节的长度,所以要定义成char类型的指针,所以(char*)pobj + 28)。此时他代表着一个地址
    //此时要把这个地址取出来,利用int*,将其转换成四字节的数据
    //最后取地址*

指针进阶

一维指针在数组的应用  

void text(int** p)
{
    for (int i = 0; i < 5; i++)
    {
        printf("%d/r/n",* (*(p + i)));
    }
}
    int** pArr = (int**)malloc(sizeof(int*) * 5);
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;
    int e = 50;
    pArr[0] = &a;
    //pArr[0] = int* p; p = &a
    pArr[1] = &b;
    pArr[2] = &c;
    pArr[3] = &d;
    pArr[4] = &e;
    text(pArr);
  

二维数组的指针应用

   二级指针 指向的每一个空间都是一个一级指针 
    //一个一维数组:int nArr1[4] = {1,2,3,4};
    //int* p
    //p = nArr1表示一维数组

    //int nArr[3][4] 含义三个一维数组,每个一维数组四个元素
    //int(*p)[4],此时int(*p)表示指向一维数组
    //p + 1 指向第二个一维数组,不再是加一个sizeof(int)
    // 而是加一个sizeof(int) * 4(加了一个一维数组的四个元素类型大小
    
    int nArr[3][4] = { {11,22,33,44},{18,99,48,44},{15,94,36,44} };
    int(*p)[4];
    p = nArr;
    for (int i = 0; i < 3; i++)
    {
        for (int k = 0; k < 4; k++)
        {
            //p[一级数组的索引] p[0] = {11,22,33,44},p[1] = {18,99,48,44}
            //p[0] = {11,22,33,44},Addr 指针加法 类型步进
            //k = 0 1 2 3 一维数组的元素地址
            //p[i] + k 地址
            //*(p[i] + k)地址上的值
            printf("%d\r\n", *(p[i] + k));
            printf("%d\r\n",*(*(p + i) + k)
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值