⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C语言初阶
⭐代码仓库:C Advanced
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!
Struct
前言
结构体在C语言当中是很重要的,这对于后续需要写教务系统和登记成员的情况是很重要的,这篇讲的是初识结构体,带领大家学习结构体入门,并逐渐掌握结构体。结构体的知识点主要包括结构体类型的声明,结构体的初始化,结构体成员访问和结构体传参。
一、结构体类型的声明
(一)结构体的基础知识
概念:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
在我们这个世界中,有很多的复杂对象,像描述一个学生,描述一本书,那么C语言编译器是怎么将这些复杂对象包含在一起的呢?如下图,接下来我们将引进struct关键字对其进行分装。
(二)结构体的声明与定义
1.定义结构体的类型
概念:结构体的成员可以是标量、数组、指针,甚至是其他结构体(结构体的嵌套)。
如下图,结构体内部是由标签名,成员列表和变量列表组成的。
我们试着创建一个结构体,如下图,根据右边需要输入学生信息来创建的结构体。
2.结构体变量的定义
(1)直接创建
当我们定义了结构体的类型,有了类型根据main函数里进行创建结构的变量,这其实相当于类型是int, float的类型,而结构体变量就是在main函数里进行创建的变量,相当于我们熟悉的int a; float b等。
(2)利用变量列表创建
记得前面讲的定义结构体的类型里的变量列表吗,它也是可以创建结构体变量的,只不过如果在main函数内部创建,这个结构体变量是一个局部变量,而在变量列表中创建结构体变量则为全局变量。
3.结构体变量的初始化
如下图:定义完结构体变量后进行初始化,这与数组类似,在一个大括号里包含结构体的类型内要输入的数据。
代码如下:
#include<stdio.h>
struct Stu {
//结构体成员
char name[20];
int age;
char sex[10];
float score;
} /*s4, s5*/; //也是结构体变量 - 全局
//struct Stu s6; //也是结构体变量 - 全局
int main() {
//struct Stu s1, s2, s3; //结构体变量 - 局部
//定义并初始化结构体变量
struct Stu s7 = { "zhangsan",20,"nan",80.0f };
struct Stu s8 = { "lisi",19,"nan",99.0f };
struct Stu s9 = { "ruhua",18,"nv",98.0f };
//打印
printf("%s %d %s %.1f\n", s7.name, s7.age, s7.sex, s7.score);
printf("%s %d %s %.1f\n", s8.name, s8.age, s8.sex, s8.score);
printf("%s %d %s %.1f\n", s9.name, s9.age, s9.sex, s9.score);
return 0;
}
(三)结构体嵌套
如下代码:
#include<stdio.h>
struct P {
double d;
float f;
};
struct S {
int a;
struct P p; //嵌套一个结构体类型P
char c;
};
int main() {
//定义结构体变量并初始化
struct S s = { 10,{3.14,3.2f},'c'};
//打印
printf("%d %.2lf %.1f %c", s.a, s.p.d, s.p.f, s.c);
return 0;
}
二、结构体成员的访问
进行结构体成员的访问,主要是两种操作符,一种是(.),另一种是(->)(链表内容),这两种操作符分别对应的是找值并进行改变和找地址并进行改变,是两种不同的访问操作符,我将在接下来的传参中细细讲解。
三、结构体传参
1.传值打印
进行传值,将结构体变量里的值进行传参到函数里,并进行打印。特别要注意的是,仅仅是结构体变量的话为结构体变量.成员。
struct P {
double d;
float f;
};
struct S {
int a;
struct P p; //嵌套一个结构体类型P
char c;
};
void Print1(struct S sp) {
//结构体变量.成员
printf("%d %.2lf %.1f %c", sp.a, sp.p.d, sp.p.f, sp.c);
}
int main() {
//定义结构体变量并初始化
struct S s = { 10,{3.14,3.2f},'c'};
//打印
//printf("%d %.2lf %.1f %c", s.a, s.p.d, s.p.f, s.c);
Print1(s);
return 0;
}
2.传址打印
进行传址,将结构体变量的地址传参到函数里并进行打印。特别要注意的是,如果是结构体指针的话,只需要结构体指针->成员即可。
#include<stdio.h>
struct P {
double d;
float f;
};
struct S {
int a;
struct P p; //嵌套一个结构体类型P
char c;
};
//传值调用
//void Print1(struct S sp) {
//printf("%d %.2lf %.1f %c\n", sp.a, sp.p.d, sp.p.f, sp.c);
//}
//
//传址调用
void Print2(struct S* sp1) {
printf("%d %.2lf %.1f %c\n", (*sp1).a, (*sp1).p.d, (*sp1).p.f, (*sp1).c);
//结构体指针—>成员
printf("%d %.2lf %.1f %c\n", sp1->a, sp1->p.d, sp1->p.f, sp1->c); //结构体指针
}
int main() {
//定义结构体变量并初始化
struct S s = { 10,{3.14,3.2f},'c'};
//打印
//printf("%d %.2lf %.1f %c\n", s.a, s.p.d, s.p.f, s.c);
//Print1(s); //传值调用
Print2(&s); //传址调用
return 0;
}
3.哪者更优
ps:上面的Print1和Print2函数哪个更好?
答:首选Print2,在进行结构体传参的时候,首选结构体地址的传参。
因为函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以导致性能的下降。
如果大家对压栈不是很了解,我放一篇我自己写的博客供大家先去理解一下。
函数栈帧创建与销毁
四、scanf输入结构体变量值
struct P {
double d;
float f;
};
struct S {
int a;
struct P p; //嵌套一个结构体类型P
char c;
};
//传值调用
//void Print1(struct S sp) {
//printf("%d %.2lf %.1f %c\n", sp.a, sp.p.d, sp.p.f, sp.c);
//}
//
//传址调用
//void Print2(struct S* sp1) {
//printf("%d %.2lf %.1f %c\n", (*sp1).a, (*sp1).p.d, (*sp1).p.f, (*sp1).c);
//printf("%d %.2lf %.1f %c\n", sp1->a, sp1->p.d, sp1->p.f, sp1->c); //结构体指针
//}
int main() {
//定义结构体变量并初始化
struct S s = { 10,{3.14,3.2f},'c'};
scanf("%lf %f",&(s.p.d), &(s.p.f));
//打印
printf("%d %.2lf %.1f %c\n", s.a, s.p.d, s.p.f, s.c);
//Print1(s); //传值调用
//Print2(&s); //传址调用
return 0;
}
总结
关于结构体,大家可以理解成和int char double 一样的类型,只不过结构体可以包含的东西很多,是这些变量的一个集合,结构体在编程中是很重要的存在,这一篇博客带领大家梳理了一遍结构体的基本知识,相信大家有很深的收获!
客官读到这里了,来个三连支持一下吧!!!