结构体知识点


/// 结构体是把单一类型组合在一起的做法


/// define不是关键字,是一个预处理指令
/// 

struct Stu//这是一个类型(类似于int)通过类型创建变量,不占空间,只有变量创建出来,才能占据空间
{
    char name[20];
    int age;
    char sex[10];
    char tele[12];
};
void print(struct Stu* p)//p是指针,里面存的数据类型是地址
{
    //p中存储的是地址。而*p代表该地址指向的哪个房间的名字,(*p).name,代表该房间存储的东西
    printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", (*p).name, (*p).age, (*p).sex, (*p).tele);
    //p中存储的是地址,p->代表该地址具体的位置,也就是存储数据的那房间,p->name代表去除该房间内存储的内容
    printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", p->name, p->age, p->sex, p->tele);
}
int main()
{
    //创建结构体并进行初始化
    struct Stu s = {"张三",20,"男","15157197537"};//只有创建出来才能占据空间
    //结构体对象.变量名
    printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", s.name, s.age, s.sex, s.tele);
    print(&s);
    return 0;
}

/*
    结构是一种集合(数组是一组相同类型元素的集合)
    结构类似于对象,比如说人具有姓名,年龄,身高等属性,也具有走,跑,跳等动作


    结构是一些值的集合,这些值称为成员变量


*/
/*
    结构体声明格式
    struct 结构体名字
    {
        成员变量//成员可以是标量,数组,指针甚至是其它结构体
    }变量列表;
    变量列表可省略,变量列表的作用是在定义结构体的同时创建结构体变量
*/

//结构体的定义


//struct Peo //struct Peo是类型
//{
//    struct People p;
//    char name[20];
//    char tele[12];
//    char sex[5];
//    int high;
//};//通常采用这种方法
//struct People
//{
//    char name[20];
//    char tele[12];
//    char sex[5];
//    int high;
//}P1,P2;//P1,P2是使用struct People结构体类型创建的两个变量
此时的P1,P2是两个全局变量
//int main()
//{
//    struct Peo P3;//P3为局部变量
//
//    return 0;
//}

//结构体的初始化


//struct Peo //struct Peo是类型
//{
//    char name[20];
//    char tele[12];
//    char sex[5];
//    int high;
//};
//struct Stu
//{
//    struct Peo p;
//    int num;
//    float f;
//};
//void print1(struct Stu s)
//{
//    printf("%s %s %s %d %d %.2f\n", s.p.name, s.p.tele, s.p.sex, s.p.high, s.num, s.f);
//}
//void print2(struct Stu *h)
//{
//    printf("%s %s %s %d %d %.2f\n", h->p.name, h->p.tele, h->p.sex, h->p.high, h->num, h->f);
//}
//int main()
//{
//    //完全初始化
//    struct Peo p = { "zhangsan","15157197539","男",185 };
//    struct Stu s = { {"lisi","19825088479","女",166},100,3.14f };
//
//    printf("%s %s %s %d %d %.2f\n", s.p.name, s.p.tele, s.p.sex, s.p.high, s.num, s.f);//结构体变量.成员变量
//
//    struct Stu* h = &s;
//    printf("%s %s %s %d %d %.2f\n", h-> p.name, h->p.tele, h->p.sex, h->p.high, h->num, h->f);//结构体指针->成员变量
//
//    print1(s);//这种传参实际上是对s的一种临时拷贝,传过去之后会在栈区找一块区域存储s,这样就很浪费存储空间,浪费资源
//    print2(&s);//地址只有4/8个字节,在压栈是创建的空间相对就比较小
//    //故结构体传参时,尽量传地址,这样性能会更高一些
//    return 0;
//}

自定义类型之-结构体

    自定义类型: 结构体,联合,枚举

    结构体
    结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

    结构的声明
    struct tag //这只是一个类型,不用初始化
    {
     member-list;
    }variable-list;
    tag结构标签
    member-list;成员列表
    variable-list;变量列表,可写可不写


    匿名结构体类型--只能在创建全局变量的时候使用一次


    struct 
    {
        char name[20];
        int age;
    }s1,s2,s3; //全局变量

//struct Stu
//{
//    char name[20];
//    int age;
//}s1,s2,s3; //全局变量
//
匿名结构体类型
//struct
//{
//    int a;
//    char b;
//    float c;
//}x;
//struct
//{
//    int a;
//    char b;
//    float c;
//}a[20], * p;
//
//int main()
//{
//    struct Stu s3;//局部变量
//    p = &x;// 虽然两个匿名结构体的成员变量相同,但是还是会被编译器认为成两个不同的结构体
//    return 0;
//}

数据结构


    数据在内存中的存储结构


    线型


        顺序表:arr[10]    
            1 2 3 4 5 顺序存放

       链表

(胡乱存放,但能通过上一个数据(节点)找打下一个,如同链条一样)
        一个节点包含两个部分: 数据+下一个节点的地址
        结构体的自引用:
            struct Stu

            {
                char name[20];
                struct Stu *next;
            };
            typedef struct Stu
            {
                char name[10];
                struct Stu *next;
            }Node;
            struct Stu s1 等价于 Node s1
                1                4
                        2  3                5


    树型


        二叉树

结构体内存对齐(计算结构体内存大小)

结构体内存对齐(重要)//计算结构体的大小

    对齐规则(核心:分清什么时候使用最大对齐数,什么时候使用最小对齐数)
    1. 第一个成员在与结构体变量偏移量为0的地址处。
    2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的值为8
    3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
    4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
    体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

    //对齐的原因
    1. 平台原因(移植原因)
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
    定类型的数据,否则抛出硬件异常。
    2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
    原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
    问。

    结构体的内存对齐是拿空间来换取时间的做法

    那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
    让占用空间小的成员尽量集中在一起。

内存对齐例子

#include<stddef.h>
//struct S1
//{
//    char c1;//1
//    int i;//4 
//    char c2;//1
//};
s1内存存储情况
///*                
//总大小最大对齐数的整数倍  12
//                      偏移量   总个数
//                       --
//              c1    |    0        1   第一个成员在与结构体变量偏移量为0的地址处
//                       --
//                     |     1        2
//                     --
//                    |    2        3
//                     --
//                    |    3        4
//                     --
//                i    |    4        5  其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
//                     --
//                i    |    5        6
//                     --
//                i    |    6        7
//                     --
//                i    |    7        8
//                     --
//                c2  |    8        9
//                     --
//                    |    9        10
//                     --
//                    |    10        11
//                     --
//                    |    11        12
//                     --
//*/
//struct S2
//{
//    char c1;//1
//    char c2;//1
//    int i;//4
//};
//int main()
//{
//    //printf("%d\n", sizeof(struct S1));//12
//    //printf("%d\n", sizeof(struct S2));//8
//
//    //#include<stddef.h>
//    //offsetof(type,member);
//    //可以返回该成员在该类型中的偏移量,单位是字节
//    printf("%d\n", offsetof(struct S1, c1));//0
//    printf("%d\n", offsetof(struct S1, i));//4
//    printf("%d\n", offsetof(struct S1, c2));//8
//    return 0;
//}

offsetof(返回结构体成员相对于起始位置的偏移量)

/*


    修改默认对齐数


    #pragma  pack()//设置默认对齐数
    #pragma  pack(1) //设置默认对齐数为1
    #pragma  pack()//取消设置的默认对齐数,还原为默认

    #pragma once //防止头文件被引用多次
*/

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值