8月22日笔记C语言基础(补1)结构体2

1.结构体概念的引入
    c语言提供了众多的数据类型,但是这些数据类型远远达不到我们的需求
    比如描述学生,学生信息 : 姓名,性别,年龄。。。。,那么我们通过
    什么数据类型描述学生信息呢?答案是自定义数据类型,结构体。
    
    结构体其实是一种复合数据类型


    什么是结构体?为什么要用结构体
    结构体其实就是自定义数据类型,方便我们更好的管理数据


2.结构体的定义
    struct  结构体名
    {
        成员类型1 成员名1; int a;
        成员类型2 成员名2;
        成员类型3 成员名3;
    };
    语法:
        结构体名是用来区分不同的结构体
        成员,是包含在结构体内部的数据,只在这个结构体有效
            可以是任意数据类型
    demo:

 struct student
    {
        char name[20]; // 姓名
        char sex; // 性别
        int age; // 年龄
    };

  struct student 是我们定义的一个全新的数据类型,名为struct student
    这个数据类型包含了姓名,性别,年龄

 // 使用方式
    int main()
    {
        struct student st;
    }


3.结构体初始化
    1.普通初始化
        // 给结构体分配栈空间的同时初始化
        // 普通初始化,必须将结构体里面的内容全部初始化
        struct student st = {"Jack",'m',18};
        
        // 将结构体的里面的内容打印出来
        // 如果栈空间分配内存为普通变量,一般访问结构体里面的成员用符号(.)访问
        printf("%s,%c,%d\n",st.name,st.sex,st.age);
    //scanf("%s,%c,%d\n",st.name,&st.sex,&st.age);
    2.指定成员初始化
        // 指定成员初始化

        struct student st1 = {
            .name = "Rose",
            //.sex = 'w', // 正确
            .age = 18
        };
        printf("%s,%c,%d\n",st1.name,st1.sex,st1.age);    

   3.定义结构体的时候初始化

         struct student
        {
            char name[20];
            char sex;
            int age;
        }st2 = {"xiaoming",'M',19};
        // 定义结构体的时候就初始化
        printf("%s,%c,%d\n",st2.name,st2.sex,st2.age);

4.多结构体使用 

// 定义struct date类型
    struct date
    {
        int y; // 年
        int m; // 月
        int d; // 日
    };

    struct student
    {
        int age;
        // 使用struct date
        // 给struct date 分配栈空间
        struct date birthday;
        //struct student // 重复定义
    };
    // 普通初始化
    int main()
    {
        // 普通初始化
        struct student st = {18,2003,9,19};
        printf("%d---%d/%d/%d\n",
            st.age,
            st.birthday.y,
            st.birthday.m,
            st.birthday.d
            );
        return 0;
    }
    
    //-------------------------    
    // 指定成员初始化    
    int main()
    {    
        // 指定成员初始化    
        struct student st1 = {
            .age = 19,
            .birthday.y = 2003,
            .birthday.m = 10,
            .birthday.d = 11,
        };
        printf("%d---%d/%d/%d\n", \
            st1.age, \
            st1.birthday.y, \
            st1.birthday.m, \
            st1.birthday.d
            );    
            
        return 0;
    }

5.结构体成员引用
    结构体成员的引用和普通变量使用没有任何区别

 struct student
    {
        char name[20];
        int age;
        char sex;
    };

    int main()
    {
        struct student st;
        // 错误,不能直接给数组赋值
        //st.name = "jack";
        strcpy(st.name,"jack");
        char buf[20];
        //buf = "Rose";// 错误的
        strcpy(buf,"Rose");
        st.age = 18;
        st.sex = 'm';
        
        printf("%d,%c,%s\n",st.age,st.sex,st.name);
        
        return 0;
    }

6.结构体指针,重点
    和普通变量的指针没有任何区别
    demo:   

 struct student
    {
        char name[20];
        int age;
        char sex;
    };

    int main()
    {
        // 需要分配堆空间,否则段错误
        struct student *st = malloc(sizeof(struct student));
        // 注意结构体指针访问成员的时候是用符号(箭头)表示
        strcpy(st->name,"jack");
        printf("%s\n",st->name);
        
        
        // 释放堆空间
        free(st);
        st = NULL;
        
        struct student a;
        struct student *q = &a;
        (*q).age = 18;// ==> a.age;
        int d = 10;
        int *p = &d; // *p = 10;d = 10
        q->age = 18;
        
        printf("%d\n",q->age); // 指针访问成员用箭头->
        printf("%d\n",(*q).age); // 普通变量访问成员用.
        
        return 0;
    }


7.结构数组

     int a[5]; a[0] = 1; a[1] = 2; a[2] = 3;
    struct student class[5];
    
    // 结构体数组普通初始化
    struct student
    {
        char name[20];
        int age;
        int score;
    }st[3] = {
        {"jack",18,80},
        {"Rose",17,85},
        {"xiaoming",19,60}
    };
    void main()
    {
        printf("%s,%d,%d\n",st[0].name,st[0].age,st[0].score);
        printf("%s,%d,%d\n",st[1].name,st[1].age,st[1].score);
        printf("%s,%d,%d\n",st[2].name,st[2].age,st[2].score);
    }
        
    // 结构体数组指定成员初始化
    struct student1
    {
        char name[20];
        int age;
        int score;
    };
    
    void main()
    {
        // 指定成员初始化
        struct student class[3] = {
            //class[0]
            {
                .name = "jack",
                .age = 18,
                .score = 90
            },
            //class[1]
            {
                .name = "jack",
                .age = 18,
            },
            //class[2]
            {
                .name = "jack",
                .score = 18,
            }
        };
    
        printf("%s,%d,%d\n",class[0].name,class[0].age,class[0].score);
        printf("%s,%d,%d\n",class[1].name,class[1].age,class[1].score);
        printf("%s,%d,%d\n",class[2].name,class[2].age,class[2].score);
    }
    
    // 引用结构体数组里面的成员
        struct student1
        {
            char name[20];
            int age;
            int score;
        };
        void main()
        {
            struct student class1[3];
            strcpy(class1[0].name,"jack");
            
            class1[0].age = 18;
            class1[0].score = 90;
            printf("%s,%d,%d\n",class1[0].name,class1[0].age,class1[0].score);
            
            scanf("%s%d%d",(class1+1)->name,&class1[1].age,&class1[1].score);
            scanf("%s%d%d",(*(class1+1)).name,&class1[1].age,&class1[1].score);
            printf("%s,%d,%d\n",class1[1].name,class1[1].age,class1[1].score);
        
        }



//练习2:
//    定义一个学生信息结构体数组(数组元素的个数由用户决定),依次从键盘输入每个学生
//    信息(姓名,成绩),按成绩的降序输出每个学生的信息,降序算法最好是自己封装函数
//    dmeo:
    #include <stdio.h>
    #include <string.h>

    struct student
    {
        char name[20];
        int score;
    };

    void sort(struct student *st,int len)
    {
        int tmp;
        char tName[20] = {0};
        
        for(int i = 0; i < len-1;i++)
        {
            for(int j = 0; j < len-i-1; j++)
            {
                if(st[j].score < st[j+1].score)
                {
                    tmp = st[j].score;
                    strcpy(tName,st[j].name);
                    
                    st[j].score = st[j+1].score;
                    strcpy(st[j].name,st[j+1].name);
                    
                    st[j+1].score = tmp;
                    strcpy(st[j+1].name,tName);
                    
                }
            }
        }
        
        
    }

    int main()
    {
        struct student st[3];
        
        for(int i = 0;i < 3;i++)
            scanf("%s%d",st[i].name,&st[i].score);
        
        int len = sizeof(st) / sizeof(struct student);
        
        sort(st,len);
        
        for(int i = 0; i < len; i++)
            printf("%s,%d\t",st[i].name,st[i].score);
        
        printf("\n");
        
        return 0;
    }


8.结构体封装
    结构体一般都是在头文件定义
    demo:

    #ifndef _MYHEAD_H
    #define _MYHEAD_H

    #include <stdio.h>
    #include <stdlib.h>

    typedef int dataType;
    //typedef int * pdataType;

    //int data;// == dataType data;

    //int *p; // == pdataType p;


    // 定义结构体类型
    typedef struct node
    {
        int age;
        char sex;
        dataType data;
        
    }newNode,*pnewNode;// 等价于 typedef struct node newNode;  typedef struct node *pnewNode

    #endif
//------------------------------------
    #include "myhead.h"

    int main()
    {
        //struct node myNode;
        newNode myNode;
        myNode.age = 18;
        myNode.sex = 'M';
        myNode.data = 123;
        printf("%d,%c,%d\n",myNode.age,myNode.sex,myNode.data);


        //struct node *newNode;
        pnewNode newNode = NULL; // 指针变量
        newNode = malloc(sizeof(pnewNode));
        newNode->age = 18;
        newNode->sex = 'W';
        newNode->data = 456;
        printf("%d,%c,%d\n",newNode->age,newNode->sex,newNode->data);
        return 0;
    }

总结:
    此处typedef如果用在结构体上,可以将这个结构体类型
    改为普通变量类型,也可以改为指针变量类型,这样的
    好处是第一可以增加代码的可读性,第二让结构体使用起来
    比较方便


9.字节对齐(笔试题考的较多)
问题引入?
    int a; // 4字节
    char b; // 1字节
    short c;// 2字节
    
    那么
    struct node
    {
        int a; // 4
        char b; // 1
        short c; // 2
        
    };
    sizeof(struct node)大小??
    
    struct node
    {
        char a; // 1
        char b; // 1
        short c; // 2
    };
    
    字节对齐概括:
        系统为了提高执行效率,计算机从内存中取数据是按照固定的长度取的,比如
        32位系统是最大4字节取数据(注意字节对齐方式是可以手动修改),如果是64位系统得看数据的最大长度(long double),如果数据
    
    结构体的存储数据的方式是以成员的最大值为参考值俗称M值
        结构体的M值是以对应成员的最大值决定,当然32位系统的M值最大为4
        例如:
        struct node
        {
            short a; // 尺寸=2,M值为2
            double b; // 尺寸=8;32位系统下M值为4,64位系统M值为8
            char c; // 尺寸=1,M值为1
        };
        struct node n;
        32位系统 M值 = max{2,4,1} = 4 
            4+8+4 = 16        16/m=0
            
        64位系统 M值 = max{2,8,1} = 8 
            8+8+8 = 24        24/m=0    
            
            
    字节对齐总结
        1.找结构体里面最大的M值
    2.在将结构体里面的数据从上往下依次按照自己的M值方式存储,如果存的地址大于M值,就换行


    将结构体的空间大小设置成实际成员空间之和
    #pragma pack(1) // 将M值设置为1,将此文件下的所有结构体大小设置为实际成员的大小之和
    struct node2
    {
        short a; 
        
        char c;
        
        double b;

    }__attribute__((packed));
    
    __attribute__((packed))的作用是将结构体大小设置为实际成员大小之和


设置结构体成员的M值、

   #include <stdio.h>
    #include <stdint.h>
    struct node 
    {
        int8_t a __attribute__((aligned(16))); // 其实就是char类型  1字节
        int64_t b __attribute__((aligned(8)));// 其实就是 long 类型  8字节
        int16_t c __attribute__((aligned(2)));// 其实就是short类型   2字节
        
    };

    int main()
    {
        struct node st;
        printf("%ld\n",sizeof(int8_t));
        printf("%ld\n",sizeof(int64_t));
        printf("%ld\n",sizeof(int16_t));
        
        printf("%ld\n",sizeof(st));
        
        
        return 0;
    }
 



    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值