嵌入式0基础开始学习 ⅠC语言(8)结构体

0.问题引入

         C语言是允许程序员定义自己的组合类型
                       构造类型  =》 数组
                                              结构体
                                              枚举
                                              共用体/联合体
            现实世界的物体需要抽象成计算机语言中的数据类型(对象)
            学生:
                    学号 ==> int num;
                    姓名 ==> char name[32];
                    性别 ==> char gender;
                    年龄 ==> int age;
                    .....
                把这些物体的属性组合到一个数据类型中去,用来表述“学生”这样的类型
                       结构体
                      

1.结构体:  自定义的一种类型

         1.1  struct 结构体名

               {
                    成员类型1   成员名1;
                    成员类型2   成员名2;
                    ....
                    成员类型n   成员名n;
               };
               结构体类型是由多个成员构成,而且每个成员都有自己的类型(只要是合法的类型都可以)
               不同的成员,类型可以相同,但是成员名不能相同!!!
               
               struct 结构体名 ==> 定义的新类型的名字。
               
               struct student
               {
                ......
               };
               struct student 是我们新定义的类型名,
                      这样的类型是用来描述”学生“的
                    
                     定义变量:
                             变量的类型 变量名;
                             struct student s ; // s就是一个结构体变量
                                                // typeof(s) ==> struct student
                    
                    "成员类型1,成员类型2....." ;
                            只要是c语言中合法的类型都可以。
                            可以是基本类型/构造类型/指针......
                    “成员名1,成员名2....“
                            只要符合c语言标识符的规定,成员名之间不能相同。
                            
                例子:
                       构造一个”学生“这样的结构体类型。
                       ”学生“:
                               学号,姓名,性别,年龄,成绩
                            struct student
                            {
                                int num; //学号
                                char name[32];//姓名
                                char gender; // 性别
                                int age ; // 年龄
                                float score ;// 成绩
                            };
                            上面的语句,构造了一个新的类型 :struct student
                            并且这个新类型里面包含了 num ,name,gender,age,score这些成员变量。
                            
                                 如果要定义一个新类型的变量s(结构体变量)
                                 变量的类型 变量名 {=初始值};
                                 struct student s { = 初始值};
                                 此时,s里面会有一个int类型的num,name.....
                                
                            问题:   这些成员变量在内存中是如何分布的呢?
                           

         1.2结构体成员的内存布局

                (1)结构体类型所占空间是各个成员变量所占空间之和
                (2)结构体内各个成员变量按他们定义时出现的次序,依次排列              

         1.3结构体变量的引用

                结构体内部的成员变量的引用
                
                (1) .
                         域操作符 :取某个子成员变量
                         用法:
                                 结构体变量名 . 成员名
                        例子:
                                struct student s; //(s=>num,name,gender,....)
                                
                                s.num = 115200 ;// write
                                int n = s.num; // read
                                
                                s.name
                                s.gender
                                s.age
                                s.score
                                ....
                            引用成员变量和普通变量是一样的,他们既有左值,也有右值!
                        
                        可以定义一个指针,来保存s的地址:
                            指向对象的类型 * p;
                            typeof(s) *p;
                            ===>struct student *p; //p就是一个结构体指针
                                 p = &s; //保存了结构体变量s的地址,p指向s
                                
                        想通过指针p来访问s里面的成员变量
                        
                (2)(*结构体指针).成员变量名
                      (*p). num
                      .....
                (3)->
                        结构体指针 -> 成员变量名
                   
            练习:
                 1.定义一个结构体类型来描述一个日期(年,月,日)
                   再定义一个结构体类型来描述一个学生(姓名,成绩,出生年月日,年龄)
                    
                    请大家再main函数中,定义一个学生类型的变量
                    从键盘给这个结构体变量的成员赋值,
                    再输出这个结构体变量中各个成员的信息。
                    //日期
                   struct date
                   {
                       int year;
                       int month;
                       int day;
                   };

                   struct student
                   {
                     char name[32];
                     int  score;
                     struct date birthday; ----> &s.birthday.year  &s.birthday.month  &s.birthday.day
                     int age;
                   };                  
                   int main()
                   {
                      struct student s;
                       scanf("%s %d %d-%d-%d %d", s.name , &s.age, &s.brithday.year ,
                            &s.brithday.month, &s.brithday.day, &s.score);
                       printf("%s %d %d-%d-%d %d\n", s.name , s.age, s.brithday.year ,
                            s.brithday.month, s.brithday.day, s.score );
                   }

         1.4初始化结构体变量的方法

                定义结构体变量时候就赋值        

                      struct date
                   {
                       int year;
                       int month;
                       int day;
                   };
                     struct student
                   {
                     char name[32];
                     int  score;
                     struct date birthday;
                     int age;
                   };        

            (1)按照定义时的顺序依次初始化各个成员变量,用逗号隔开。
                     struct student s =
                     {
                        "yangyang",
                         88,
                        {2010,12,12},
                        13                        
                     };

             (2)不按照顺序, .成员变量名 = 值 ,用逗号隔开
                    struct student s =
                     {
                        .score = 88,
                        .birthday = {2010,12,12},
                        ....
                        
                     };    
                    
              (3)结构体数组初始化
                   a,按照数组元素的顺序依次初始化
                         struct student class[3] =
                      {
                          // class[0]
                             {
                                 .name = xxx,
                                 .age = xxx,
                             },
                          // class[1]
                             {
                                 xxxxx
                             }
                          
                      };
                    b,不按照数组元素的顺序。  [下标] =
                       不同编译器,情况或限制不一样
                     struct student class[3] =
                      {  
                           [1] =
                                 {xxxxx},
                           [0] =
                                  {xxxx},
                      };
                      
            练习: 定义一个结构体来描述一个学生的信息(学号,成绩,姓名,出生年月日)
                   从键盘中输入5个学生的信息,假设按成绩的降序依次输出每个学生的信息
                   struct date
                    {
                        int y, m , d;
                    };

                    struct student
                    {
                        int num;
                        char name[32];
                        int score;
                        struct date  birthday;
                    };
                    int main()
                    {
                       struct student *pcls = (struct student*)malloc(5*sizeof(*pcls));
                       // p[0] ... p[4]
                       //从键盘给每一个学生进行输入
                       int i;
                       for(i=0;i<5;i++)
                       {
                          scanf("%d %s %d %d-%d-%d",
                                 &pcls[i].num,
                                 pcls[i].name,
                                 &pcls[i].score,
                                 &pcls[i].birthday.y,
                                 &pcls[i].birthday.m,
                                 &pcls[i].birthday.d);
                       }
                       //可以按照学生的成绩,由大到小排序
                       int a[5]; //保存pcls元素的下标
                                 // a[0] 成绩最高的那个学生所在数组pcls中的下标
                                    ...
                                    a[4] 成绩最低
                        for(int i = 0;i<5;i++)
                        {
                           a[i] = i;
                        }
                        for(int j = 1;j<5;j++)
                        {
                            for(i = 0; i <5-j;i++)
                            {
                                if(pcls[a[i]].score < pcls[a[i+1]].score)
                                {
                                   struct student s;
                                    s = pcls[i];
                                    pcls[i] = pcls[i+1];
                                    pcls[i+1] = s;
                                }
                            }
                        }
                        for(i=0;i<5;i++)
                        {
                           printf("%d %s %d %d-%d-%d",
                                      pcls[i].num,
                                     pcls[i].name,
                                     pcls[i].score,
                                     pcls[i].birthday.y,
                                     pcls[i].birthday.m,
                                     pcls[i].birthday.d );
                        }
                    }

2.共用体/联合体

        语法:
                union 共用体名
                {
                   成员类型1   成员名1;
                   成员类型2   成员名2;
                   ......
                   
                };
                
        共用体与结构体最大的区别:
                      结构体所占内存大小是各个成员变量之和
                      共用体所占内存大小是各个成员变量中所占内存最大的那个
                      
                union  t
                {
                     int a;
                     char b;
                     short c;
                };
                sizeof(union t) == 4
                
        共用体的存储空间是各个成员之间共用的,
        同一时刻只能用一个成员变量,为了节省内存才提出 共用体
            例子:
                  union test                  
                  {
                      int a;
                      int b;
                  };
                  sizeof(union test) == 4
                  占四个字节的空间,成员变量a和b共用这四个字节。
            
                union test
                {
                   char a;
                   int b;
                };
                union test t;
                t.b = 256;
                t.a = ? // 0
                
        大端模式和小端模式
                CPU寄存器是按bit位来存储信息的,
                寄存器的数量是非常有限的
                我们经常会把寄存器中的数组存储到存储器(内存)中去
                内存不是按bit来寻址,按字节编号(地址)去寻址
                
                如果把寄存器中的内容存储到内存中去,那么内存的
                低地址到底是保存寄存器中的  低字节还是高字节呢?
                
                大端模式:
                          存储器的低地址,存放的寄存器的高字节
                          低地址   ---------  高地址   // 0x12 34 56 78
                          高字节   ---------  低字节   // 0x12 0x34 0x56 0x78
                小端模式:
                          存储器的低地址,存放的寄存器的低字节
                          低地址   ---------  高地址   // 0x12 34 56 78
                          低字节   ---------  高字节   // 0x78 0x56 0x34 0x12

                    共用体的存放顺序是所有成员都从低地址开始存放的,利用该特性就可以
                    轻松获得我们的电脑是属于大端模式还是小端模式

                    练习;
                            请大家写一个程序,验证一下自己的电脑是属于大端模式还是
                            小端模式
                            
                            union test
                            {
                               char a;
                               int b;
                            };
                            int main()
                            {
                                union test t;
                                t.b = 1;
                                if(t.a==1)
                                {
                                   //小端
                                }
                                else
                                {
                                  //大端
                                }
                            }                            
                        小端模式
                                如下代码,请分析程序的运行结果
                                 union  test
                                 {
                                    char a;
                                    int b;
                                 };
                                 union test t;
                                 t.b = 255;
                                 t.b++;
                                 printf("%d\n",t.a); //0

3.枚举

        把该类型变量所有可能的值 一一列举出来。
        所以枚举类型一定是可以列举的值,整数值

            例子:
                    int weekday; // 星期几
                                // 1,2,3,4,5,6,7
        枚举语句:
                  enum 类型名
                  {
                     //枚举的具体的值
                  };                
                  c语言在实现枚举时,枚举的具体的值,必须要用整数来表示    。
                例子:
                        enum weekday
                        {
                             MON = 1,
                             TUE = 2,
                        };                        
                       
                        enum color
                        {
                            RED,   // 0
                            GREEN,  //1
                            YELLOW, // 2
                            PINK, // 3
                            LAN, // 4
                        };
                        enum color c = RED;
                        printf("%d\n",RED);//0
                        printf("%d\n",c);//0
                      
                        enum color
                        {
                            RED=1,
                            GREEN, //2
                            YELLOW=250,
                            PINK, // 251
                            LAN,  // 252
                        };
                        enum color c = RED;
                        printf("%d\n",RED);
                        printf("%d\n",c);
        --------------------------------------
            构造类型:
                        结构体
                        共用体
                        枚举
                        数组
                              int a[4];//定义了一个数组a,typeof(a) ===> int [4]

4.typedef

        typedef 用来声明一个新类型
                来替换一个已经有的类型

语法:
        typedef  现有的类型名 新类型名;
      ==> 新类型名 就和  现有的类型名  类型是一样的
        
        例子:
                struct student
                {
                
                };    
                typedef struct student STU;
                STU s;
                     <===> struct student s;                
                
                typedef struct student
                {
                   
                }STU;    
            --------------------------------
        int num[100];//定义了一个数组,数组名为num
             //typedef int[100] type_num;    
                 ====>typedef int type_num[100];
                     type_num:新的类型名,像num这样的类型 ---》int [100]
 
                假设让你定义一个和num一样类型的变量a:
                typeof(num) a;
                  type_num a;
                              <====>  int a[100];

     typedef 总结
                 编程定义一个新类型。
                 int a;// a是一个变量
                 typedef int a; //a就是一个类型名,像int一样的类型

5.字节对齐问题

        cpu底层为了访问的效率,一般会要求,任何对象的地址必须是对齐的

    自然对齐:
              数据地址是数据长度的倍数
             sizeof(int) ==4
             int a;
             &a 不是4的倍数的话,a不是自然对齐
            
             sizeof(short) == 2
             short a;
             &a 不是2的倍数的话,a就不是自然对齐
            
        n---字节对齐
            地址是n的倍数(n一般为2的x次幂)
             如:
                   4 - 字节对齐
                   8 - 字节对齐
                   ......
        
        结构体的每一个成员变量通常会有一个默认的对齐方式----自然对齐
                struct test
                {
                    char a; // a的地址必须是1的倍数                    
                    int b;  // b的地址必须是4的倍数
                };
                sizeof (struct test)  ==  ?8
                    a _ _ _
                    b b b b
                
                
                struct test
               {
                  char a; //
                  short b;//
                  int c; // 4                      
               };
               sizeof(struct test) == ? //8
               struct tese 是几字节对齐??
               
               在64bits x86的编译器中
                      GNU(gcc):
                               char  ---> 1字节对齐
                               short ---> 2字节对齐
                               int   ---> 4字节对齐
                               long  ---> 8字节对齐
                               float ---> 4字节对齐
                               double---> 8字节对齐
                               .....
                               指针类型 ---> 8字节对齐
                               
        练习:
                struct MixedData
                {
                   char D1;
                   short D2;
                   int D3;
                   char D4;                   
                };
                sizeof(struct MixedData)==? // 12
                   D1 _ D2 D2 D3 D3 D3 D3 D4 _ _ _
                   
                   D1 _ D2 D2
                   D3 D3 D3 D3
                   D4 _ _ _
            ---------------------------------                
                struct FinalPad
                {
                   float x;
                   char n[1];
                };
                sizeof(struct FinalPad) ==?  8
                   x x x x
                   
            -----------------------------------                
                struct FinalPadShort
                {
                   short x;
                   char n[3];
                };
                sizeof(struct FinalPadShort)==? 6
                   x x _
                   n0 n1 n2
            ------------------------------------    
                struct MixeData
                {
                    char D1;
                    short D2;
                    int D3;
                    char D4;
                };
                    s _ _ _
                    D1 _ D2 D2
                    D3 D3 D3 D3
                    D4 _ _ _
                struct test
                {
                   char s; // 1字节对齐
                   struct MixeData m;//4字节对齐
                };
                结构体是按照最大的原始类型的对齐方式对齐。
                sizeof(struct test) ==?   16          

以下对枚举类型名的定义中正确的是?   (B)

A  enum a={one,two,three};

B enum a {one=9,two=-1,three};

C enum a={"one","two","three"};

D enum a {"one","two","three"};

以下程序的执行结果是?(小端模式)    (266)

#include <stdio.h>

union un

{

int i;

char c[2];

};

void main()

{

union un x;

x.c[0]=10;

x.c[1]=1;

printf("\n%d",x.i);

}

以下程序的运行结果为?  (80)

typedef union student

{

char name[10];

long sno;

char sex;

float score[4];

}stu;

main()

{

stu a[5];

printf("%d\n",sizeof(a));

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/841062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vxetable 递归多级表头

在对vxetable 进行二次封装的时候&#xff0c;多级表头也是需要考虑进去的&#xff0c;所以需要封装一个递归列组件进行多级表头的一个渲染。 // my-table.vue <vxe-tableref"xTable":key"currentKey":data"pageData?.list || []"show-head…

Flutter 中的 MergeableMaterial 小部件:全面指南

Flutter 中的 MergeableMaterial 小部件&#xff1a;全面指南 Flutter 提供了丰富的 Material Design 组件&#xff0c;用于构建具有丰富交互和视觉效果的用户界面。MergeableMaterial 是 Flutter 中一个特殊的组件&#xff0c;它允许多个 Material widget&#xff08;如按钮、…

2024-5-25

今日安排&#xff1a; 前面的状态不太好&#xff0c;后面一定要好好调整 重新开始审计 nf_tables 源码&#xff0c;并在审计的过程中复现历史漏洞【 && iptables 相关学习】♥♥♥♥♥复现 CTF 相关题目♥♥♥♥学习 winpwn♥♥♥♥mount 的使用&#xff0c;学习 nam…

js 根据日期获取星期几

js 根据日期获取星期几 方法一&#xff1a;使用Date对象中的getDay()方法 function getWeekday(dateStr) {const weekDays [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六];const date new Date(dateStr);const weekday date.getDay();return weekDays[weekday…

MySQL造数据占用临时表空间

在数据库性能测试和开发过程中&#xff0c;常常需要生成大量的测试数据以模拟真实环境。在MySQL中&#xff0c;造数据的过程可能会占用大量的临时表空间&#xff0c;这可能会影响数据库的性能和稳定性。本文将深入探讨MySQL造数据时临时表空间的使用情况&#xff0c;并通过多个…

GolangFoundation

GolangFoundation 一. Hello World1.1 SDK1.2 环境1.3 hello world1.4 语法规则二. 变量2.1 变量声明与定义一. Hello World 1.1 SDK https://golang.google.cn/dl/下载最新版1.2 环境 GoGOROOT D:\Dev\

家政项目day2 需求分析(模拟入职后熟悉业务流程)

目录 1 项目主体介绍1.1 项目背景1.2 运营模式1.3 项目业务流程 2 运营端需求2.1 服务类型管理2.2 服务项目&#xff08;服务&#xff09;管理2.3 区域管理2.4 区域服务管理2.5 相关数据库表的管理2.6 设计工程结构2.7 测试接口&#xff08;接口断点查看业务代码&#xff09; 1…

【机器学习与大模型】开源大模型和闭源大模型:技术发展与社会责任的平衡点

目录 &#x1f4a1;引言✈️✈️一&#xff0c;开源大模型的优势与劣势✈️✈️1.1 优势&#xff1a;✈️✈️1.2 挑战和劣势&#xff1a; &#x1f680;&#x1f680;2. 闭源大模型的优势与劣势&#x1f680;&#x1f680;2.1 优势&#xff1a;&#x1f680;&#x1f680;2.2 …

所有笔记总结目录

算法篇&#xff08;C&#xff09; 算法链接基础知识基础算法总结-CSDN博客数据结构数据结构总结-CSDN博客搜索与图论搜索与图论总结-CSDN博客数学知识数学知识总结-CSDN博客动态规划动态规划总结&#xff08;闫氏Dp分析法&#xff09;-CSDN博客贪心贪心算法总结-CSDN博客 基础…

动态计算rem

前言: 最近导师布置了一些作业&#xff0c;其中有一个就是动态计算rem&#xff0c;我想到了两个版本&#xff0c;一种是不添加防抖&#xff0c;当视口发生变化时&#xff0c;就立即进行计算rem&#xff0c;还是一种就是使用防抖&#xff0c;当视口连续100毫秒没有发生变化时计…

【pyspark速成专家】7_SparkSQL编程1

目录 一&#xff0c;RDD&#xff0c;DataFrame和DataSet对比 二&#xff0c;创建DataFrame 本节将介绍SparkSQL编程基本概念和基本用法。 不同于RDD编程的命令式编程范式&#xff0c;SparkSQL编程是一种声明式编程范式&#xff0c;我们可以通过SQL语句或者调用DataFrame的相…

YoloV8改进策略:蒸馏改进|MimicLoss|使用蒸馏模型实现YoloV8无损涨点|特征蒸馏

摘要 在本文中&#xff0c;我们成功应用蒸馏策略以实现YoloV8小模型的无损性能提升。我们采用了MimicLoss作为蒸馏方法的核心&#xff0c;通过对比在线和离线两种蒸馏方式&#xff0c;我们发现离线蒸馏在效果上更为出色。因此&#xff0c;为了方便广大读者和研究者应用&#x…

amis 联动效果触发的几种方式

联动效果实现主要俩种方式: 1.表达式实现联动,基于组件内或数据链的变量变化的联动 比如&#xff1a; "source": "/amis/api/mock2/options/level2?name${name} " (必须是这种字符串拼接形式,在data数据映射中表达式不会触发联动) 所有初始化接口链…

【c++基础】分书问题

说明 已知有n本书&#xff08;从1&#xff5e;n编号&#xff09;和n个人&#xff08;从1&#xff5e;n编号&#xff09;&#xff0c;每个人都有一个自己喜爱的书的列表&#xff0c;现在请你编写一个程序&#xff0c;设计一种分书方案&#xff0c;使得每个人都能获得一本书&…

AI专业面经

AI专业面经&#xff08;部分&#xff09; 一、数学部分&#xff1a; 1.1 代数&#xff08;Algebra&#xff09;和分析&#xff08;Analysis&#xff09;&#xff1a;复习基本的代数和微积分概念&#xff0c;如线性代数、微分、积分等。 1.1.1 Algebra 1.1.1.1 基础知识 Rea…

Java进阶学习笔记10——子类构造器

子类构造器的特点&#xff1a; 子类的全部构造器&#xff0c;都会先调用父类的构造器&#xff0c;再执行自己。 子类会继承父类的数据&#xff0c;可能还会使用父类的数据。所以&#xff0c;子类初始化之前&#xff0c;一定先要完成父类数据的初始化&#xff0c;原因在于&…

线程生命周期

创建线程的两种方法 1.继承Thread类 2.实现Runnable接口 线程从创建到消亡分为新建、就绪、运行、阻塞、死亡5种状态。 新建状态 创建一个线程就处于新建状态。此时线程对象已经被分配了内存空间&#xff0c;并且私有数据也被初始化&#xff0c;但是该线程还不能运行。 就…

EventSource

什么是EventSource EventSource 是一个用于服务器推送事件&#xff08;Server-Sent Events, SSE&#xff09;的接口&#xff0c;它允许服务器推送实时更新到浏览器。与 WebSocket 不同&#xff0c;SSE 是单向的&#xff08;服务器到客户端&#xff09;&#xff0c;适用于更新频…

03-02-Vue组件之间的传值

前言 我们接着上一篇文章 03-01-Vue组件的定义和注册 来讲。 下一篇文章 04-Vue&#xff1a;ref获取页面节点–很简单 父组件向子组件传值 我们可以这样理解&#xff1a;Vue实例就是一个父组件&#xff0c;而我们自定义的组件&#xff08;包括全局组件、私有组件&#xff09;…

足球走地全自动化操作软件实现过程

本次采用selenium实现自动化操作的流程 打开浏览器录入账号密码等待数据请求&#xff08;监听&#xff09;有新数据&#xff0c;进行自动化操作通过homeName搜索&#xff0c;找到对应数据找到对应的类型&#xff08;让、大小…&#xff09;找到对应的盘口输入数量提交 附登录…