嵌入式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));

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值