嵌入式学习日志(十一)
11 学习结构体
1 结构体
1.1 类型定义
struct 结构体名 {
数据类型 成员变量1;
数据类型 成员变量2;
// ...
};
注意:结构体类型定义一般放在 main 函数外。
示例:
struct date {
int year;
int month;
int day;
};
定义了一个名为 date 的结构体类型,包含 year 、 month 、 day 三个成员变量。
1.2 结构体变量定义
struct 结构体名 变量名;
示例:
struct date d;
定义了一个 date 类型的结构体变量 d 。
也可以嵌套定义:
struct datetime {
struct date d;
struct time t;
};
定义了一个包含 date 类型成员 d 和 time 类型成员 t 的 datetime 结构体类型。
1.3 结构体元素初始化
1、全部初始化:
struct student stu = {"zhangsan", 'm', 18, 90};
2、局部初始化:
struct student stu = {
.name = "zhangsan",
.score = 90
};
没有指定初始值的成员会被赋值为0。
1.4 结构体成员访问
1、结构体变量类型:
结构体变量名.成员变量名
示例:
struct date dt;
dt.year = 2025;
dt.month = 7;
dt.day = 29;
printf("Date: %d-%d-%d\n", dt.year, dt.month, dt.day);
在这个例子中, dt 是一个 struct date 类型的变量,使用 . 操作符来访问并设置 dt 的 year 、 month 和 day 成员变量。
2、结构体指针类型:
结构体指针变量名->成员变量名
示例:
struct student *pstu = &stu;
printf("%s\n", pstu->name);
在这个例子中, pstu 是一个指向 struct student 类型变量 stu 的指针,使用 -> 操作符来访问并打印 stu 的 name 和 age 成员变量。
3、注意事项:
1、当访问结构体的成员变量时,表达式的最终类型是由该成员变量的类型决定的,而不是结构体本身的类型。例如:
struct student {
char name[50];
int age;
float score;
};
struct student stu;
stu.age = 20;
在这个例子中, stu.age 的类型是 int ,因为 age 成员变量的类型是 int 。无论结构体本身是什么类型,访问成员变量时的类型都是该成员变量的类型。
同样地,如果有一个指向结构体的指针:
struct student *pstu = &stu;
pstu->score = 95.5;
pstu->score 的类型是 float ,因为 score 成员变量的类型是 float 。
2、确保在访问结构体成员之前,结构体变量或指针已经正确初始化。
3、如果一个结构体指针想通过解引用指针来访问成员变量,也可以使用 (*结构体指针变量名).成员变量名 的形式,但这种方式不如 -> 操作符简洁。
4、对于嵌套结构体(结构体中包含另一个结构体作为成员),可以连续使用 . 或 -> 操作符来访问嵌套结构体的成员。例如:
struct datetime {
struct date d;
struct time t;
};
struct datetime dt;
dt.d.year = 2025;
dt.t.hour = 12;
或者通过指针:
struct datetime *pdt = &dt;
pdt->d.year = 2025;
pdt->t.hour = 12;
1.5 结构体的存储
结构体的存储遵循内存对齐原则:
- 结构体成员必须存放在内存地址为自身类型整数倍的内存单元中(为保证CPU一次性把数据取完)。
- 结构体大小必须为自身最大类型的整数倍( float 、 double 也用 int 或 long 等整数倍来对齐)。
示例:
struct student {
char name[32];
char sex;
int age;
int score;
};
sizeof(struct student) 的大小为44,而不是各成员变量大小简单相加(32 + 1 + 4 + 4 = 41)。
1.6 结构体传参
结构体传参时,建议使用指针传参,避免大空间拷贝。
示例:
struct student ret;
memset(&ret, 0, sizeof(ret));
使用 memset 函数将结构体 ret 的所有成员初始化为0。