嵌入式第十天:结构

今天来说一下C语言里的结构体(struct)、共用体(l联合体)union、枚举。
欢迎加入嵌入式学习群:559601187

(一)结构体:struct

1.1 概念

  • 是一种自定义的数据类型
  • 结构体是构造类型的一种
  • 不同数据类型的集合
  • 地址空间连续,每次分配最大数据类型的宽度
  • 占用内存为所有变量的总大小(注意字节对齐问题)

1.2 定义

1.先定义结构体类型,再说明结构体变量

struct stu
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
};
struct stu  student;

上面的程序使用strcuct关键字定义了一个结构体名为stu的结构体类型。和定义变量一样,声明一个结构体类型变量可以使用:数据类型 变量名 的形式。
struct stu student表示定义了一个变量名为stduent,类型为stu的结构体。该结构体含有4个成员:name、num、age、score
注意大括号后面的分号;不能少,这是一条完整的语句。
2.定义结构体类型的同时定义结构体变量

struct stu
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
}student;

在定义时直接声明结构体变量,只需要将结构体变量名放在花括号后面,并加上分号即可。
3.直接说明结构体变量

struct 
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
} student;

这种定义方式并不常用,这样做书写虽然简单,但是因为没有结构体名,后面就没法用该结构体定义新的变量。
4.typedef重定义

typedef struct 
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
} STU;
STU student;

这种方式比较常见,我们使用typedef重定义结构体为STU,这里STU就是此结构体类型,可以用STU去定义结构体变量

1.3 初始化

1.在定义结构体变量的时候全部初始化

struct stu
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
}student={“ha”,1234,56,99};

2.定义完结构体变量后,之后只能单个赋值

struct stu
{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
};
struct stu  student;
student.name="ha";
student.num=1234;
student.age=56;
student.score=99;

1.4 调用

结构体变量.成员

结构体变量名+点('.')+成员就可以调用了

1.5 结构体指针

当一个指针变量指向结构体时,我们就称它为结构体指针。C语言结构体指针的定义形式一般为:

struct 结构体名 *变量名;
//结构体
struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    float score;  //成绩
} stu1 = { "hah", 12, 18, 23, 136.5 };
//结构体指针
struct stu *pstu = &stu1;

注意结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给 pstu 赋值只能写作:

1.6 获取结构体成员

通过结构体指针可以获取结构体成员,一般形式为:

(*pointer).memberName

或者:

pointer->memberName

第一种写法中,.的优先级高于,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于(pointer.memberName),这样意义就完全不对了。

第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。

1.7 结构体内存分析

注意点

  1. 给整个结构体变量分配储存空间和数组一样,从内存地址比较大的开始分配
  2. 给结构体变量中的属性分配储存空间也和数组一样,从所占内存地址比较小的开始分配
  3. 定义结构体类型不会分配储存空间,只有定义结构体变量的时候才会分配储存空间
  • 结构体在分配内存的时候,会做一个内存对齐的操作
  • 会先获取所有属性中占用内存最大的属性的字节数
  • 然后在开辟出最大属性字节的内存给第一个属性,如果分配给第一个属性之后还能继续分配给第二个属性,那么就继续分配给第二个属性
  • 如果分配给第一个属性之后,剩余的内存不够分配给第二个属性了,那么会再次开辟最大属性的内存,再次分配 依次类推
#include 

int main(){

    //定义结构体
    struct Person
     {
        char name; // 1 个节点  //开辟4个字节 char 占用1个
        int age;  // 4个字节   // 剩余三个 不够int  再开辟4个字节
        int money; // 4个字节 // 再开辟4个字节
    };

    struct Person p; // 所以p = 4+4+4

    printf("sizeof(p) = %i\n",sizeof(p)); // 12个字节
    return 0;
}

(二)共用体(联合体):union

2.1概念

  • 所有变量共用一段空间
  • 每次分配按最大长度进行分配
  • 是一种构造数据类型
  • 同一时刻只能保存一个成员的值
  • 不能直接引用共用体变量名

2.2定义

它的定义和结构体一样,分为先定义共用体再说明共用体变量、在定义共用体的同时说明共用体变量、直接说明共用体变量

union 共用体名{
    成员列表
};

示例:

//先定义共用体再说明共用体变量
union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

2.3 引用

和结构体一样,通过共用体变量名 . 成员名

union data{
    int n;
    char ch;
    double f;
} a, b, c;
a.n=3;

关于共用体的详细介绍可以看下这篇文章C语言共用体(C语言union用法)详解,讲到共用体这里要说明一下大小端模式的问题。

大小端

小端模式:低地址存放低字节,高地址存放高字节
大端模式:低地址存放高字节,高地址存放低字节

(三)枚举:enum

3.1 概念

  • 作用:列举出所有的可能性,增强代码的可阅读性
  • 枚举成员都是常量
  • 不能再对已经定义好的枚举常量赋值

3.1 定义

enum 枚举名 
{
枚举变量
};

示例:

enum week
{ 
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
 };
typedef enum
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
}Date;

枚举是一种类型,通过它可以定义枚举变量:

Date a,b,c

我们也可以给每个名字都指定一个值:

enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };

更为简单的方法是只给第一个名字指定值:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };

这样枚举值就从 1 开始递增,跟上面的写法是等效的。
也可以在定义枚举类型的同时定义变量:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;

有了枚举变量,就可以把列表中的值赋给它:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;

或者:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;

特点:可以在定义枚举时给成员赋值,被赋值的成员往后依次增加1,也可以在中间改变某一个成员的值。

3.1 引用

直接使用就行,需要注意的是**枚举列表中的数据作用范围是全局的,不能在定义与它们名字相同的白能量;Mon、Tues、Wed 等都是常量,不能对它们赋值,只能将它们的值赋给其他的变量。
示例:

#include 
int main(){
    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
    scanf("%d", &day);
    switch(day){
        case 1: puts("Monday"); break;
        case 2: puts("Tuesday"); break;
        case 3: puts("Wednesday"); break;
        case 4: puts("Thursday"); break;
        case 5: puts("Friday"); break;
        case 6: puts("Saturday"); break;
        case 7: puts("Sunday"); break;
        default: puts("Error!");
    }
    return 0;
}

Mon、Tues、Wed 这些名字都被替换成了对应的数字。这意味着,Mon、Tues、Wed 等都不是变量,它们不占用数据区(常量区、全局数据区、栈区和堆区)的内存,而是直接被编译到命令里面,放到代码区,所以不能用&取得它们的地址。这就是枚举的本质。


本文章仅供学习交流用禁止用作商业用途,文中内容来水枂编辑,如需转载请告知,谢谢合作

微信公众号:zhjj0729

微博:文艺to青年

你可能感兴趣的:(嵌入式第十天:结构)