结构体
1、定义结构体与声明结构体变量
①、
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在学习小组
float score; //成绩
};
struct stu stu1, stu2; //声明
//或者
struct{ //没有写 stu
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在学习小组
float score; //成绩
} stu1, stu2;
②、一般这样创建结构体
typedef struct
{
int a;
char b;
double c;
char *p;
} Simple1;
//现在可以用Simple2作为类型声明新的结构体变量
Simple1 u1, u2[20], *u3;
2、访问结构体成员
一般变量
- 变量名.成员 比如 u1.b;
指针变量
- 变量名->成员 比如 u3->c;
3、初始化结构体成员
①、声明结构体变量以后单独初始化每个成员
②、通过集合符号对结构体变量进行初始化
③、如果结构体里面嵌套结构体,初始化括号加在嵌套里面
4、结构体嵌套
结构体里面可以声明无限个结构体
5、结构体存储
按字节对长的知识
12字节
12字节
20字节
20个字节
6、结构体封装
C语言结构体不能直接封装函数,但可以通过封装函数指针的方式来实现,下面便是我实现的具体方式,可以很方便的移植到任何编译器上测试。
/* serial.h文件 */
//定义封装函数的结构体,并声明外部引用
//对串口操作函数封装。
typedef struct
{
void begin(long);
void end();
int (*peek)();
uint8_t (*read)(void);
void (*flash)();
int (*availiable)();
void (*checkRx)();
}MarlinSerial;
extern MarlinSerial MSerial;
/* serial.c文件 */
MarlinSerial MSerial; //定义MarlinSerial类型的结构体MSerial
Serial_Init()
{
MSerial.read = &Serial_Read;
}
uint8_t Serial_Read(void)
{
printf("hello word!"); //在这里仅作测试所用,未列出真正的串口读取函数
}
/* main.c文件 */
int main(void)
{
Serial_Init();
MSerial.read(); //调用串口读取函数,目前功能为打印字符串
while(1)
{
//
}
}
重点应用
1、结构体指针
结构体指针定义与赋值(指向相同结构体的内存)
- C语言指针可以指向内存中的函数,变量,数组,结构体等
- 定义指向结构的指针,方式与定义指向其他类型变量的指针相似
我们要知道只要是存储在内存里的变量、数组,又或者是函数。编译器都会为它们分配一个地址,我们都可以通过指针变量指向这个地址,只要把指针变量定义成对应的数据类型就可以指向了。
比如说要指向字符型变量就定义成这样:unsigend char *p,当然也可以用void不指定类型,使用的时候再进行强制转换。
要指向函数就定义函数指针变量,那么结构体也能够定义变量,所以我们也可以定义结构体类型指针来指向它。
同样的定义访问结构体指针常用有2种方法:
①、
//结构体
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 };
//结构体指针
struct stu *pstu = &stu1;
②、
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;
- 注意,结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给
pstu 赋值只能写作:
struct stu *pstu = stu1;
而不能写作:
struct stu *pstu = stu1;
获取结构体指针成员
- (*pointer).memberName
- pointer->memberName
举例:
#include <stdio.h>
int main(){
struct{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;
//读取结构体成员的值
printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", (*pstu).name, (*pstu).num, (*pstu).age, (*pstu).group, (*pstu).score);
printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", pstu->name, pstu->num, pstu->age, pstu->group, pstu->score);
return 0;
}
结构体指针作为函数参数
像其他普通参数一样,结构体指针变量能传递给函数。传递结构体指针比传递值有优势。如前所述,当指针变量被传递并且如果值被修改,则在调用者作用域内更新是有效的。假定我们有一个超过15个数据成员的非常大的结构体变量,相比传递地址(这时使用指针变量),如果按值传递发送这个变量到函数将花费更多时间。
计算全班学生的总成绩、平均成绩和以及 140 分以下的人数。
#include <stdio.h>
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
}stus[] = {
{"Li ping", 5, 18, 'C', 145.0},
{"Zhang ping", 4, 19, 'A', 130.5},
{"He fang", 1, 18, 'A', 148.5},
{"Cheng ling", 2, 17, 'F', 139.0},
{"Wang ming", 3, 17, 'B', 144.5}
};
void average(struct stu *ps, int len);
int main(){
int len = sizeof(stus) / sizeof(struct stu);
average(stus, len);
return 0;
}
void average(struct stu *ps, int len){
int i, num_140 = 0;
float average, sum = 0;
for(i=0; i<len; i++){
sum += (ps + i) -> score;
if((ps + i)->score < 140) num_140++;
}
printf("sum=%.2f\naverage=%.2f\nnum_140=%d\n", sum, sum/5, num_140);
}
2、结构体数组
参考添加链接描述
所谓结构体数组,是指数组中的每个元素都是一个结构体。在实际应用中,C语言结构体数组常被用来表示一个拥有相同数据结构的群体,比如一个班的学生、一个车间的职工等。
结构体数组定义
- C语言中,定义结构体数组和定义结构体变量的方式类似,请看下面的例子
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
}class[5];
结构体数组初始化
struct stu{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
}class[5] = {
{"Li ping", 5, 18, 'C', 145.0},
{"Zhang ping", 4, 19, 'A', 130.5},
{"He fang", 1, 18, 'A', 148.5},
{"Cheng ling", 2, 17, 'F', 139.0},
{"Wang ming", 3, 17, 'B', 144.5}
};
结构体数组的使用也很简单,例如,获取 Wang ming 的成绩:
class[4].score;
修改 Li ping 的学习小组:
class[0].group = ‘B’;
举例
#include <stdio.h>
struct{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
}class[] = {
{"Li ping", 5, 18, 'C', 145.0},
{"Zhang ping", 4, 19, 'A', 130.5},
{"He fang", 1, 18, 'A', 148.5},
{"Cheng ling", 2, 17, 'F', 139.0},
{"Wang ming", 3, 17, 'B', 144.5}
};
int main(){
int i, num_140 = 0;
float sum = 0;
for(i=0; i<5; i++){
sum += class[i].score;
if(class[i].score < 140) num_140++;
}
printf("sum=%.2f\naverage=%.2f\nnum_140=%d\n", sum, sum/5, num_140);
return 0;
}
3、自引用结构体
结构体能将指针变量作为其成员字段。具体一点,我们能声明一个与包含它的结构体相同的指针变量类型的成员字段。
这部分在数据结构理解