第8章,C语言之结构体
目录
前言
C语言的是一个面向过程编程的思想,就不能像其他面向对象编程思想那样方便。面向对象重要的就是对象,对象里面包含着各种不同类型的变量以及方法。而在C语言中,从之前学过的知识点来看,就只有数组可以包含很多数据,但是数组的数据类型必须一致。那C语言有没有可以像面向对象中的对象那样,一个对象同时包含不同类型的数据呢?肯定是有的,那就是今天要学习的结构体。
一、结构体类型声明
其实结构体就是一些值的集合,这些值在结构体中被称为成员变量,并且这些成员变量的类型可以不同。不像数组那样,限制了数组的元素的类型必须要一致。
//结构体声明
struct tag
{
member - list;
}variable - list;
tag:结构体的标签,就是结构体的名称。
member - list:结构体中的成员变量列表,每个变量可以是不同数据类型。
variable - list:结构体变量名列表,就是用结构体数据类型定义的变量
我们来声明一个学生的结构体:
struct Stu
{
char name[20];
int age;
char sex[5];
};
这是一个学生的结构体,结构体的成员包括学生的姓名、年龄、性别三个主要的信息,如果还有其他的一些信息也可以往结构体中添加。这些都被称为结构体的成员变量。
结构体的成员变量可以是标量、数组、指针以及其他类型的结构体。
二、结构体的初始化
我们既然了解了结构体的声明,我们声明之后,该如何初始化呢?那下面就继续学习结构体的初始化相关的知识点。
//声明结构体
struct Stu
{
char name[20];
int age;
char sex[5];
}s1; //s1表示声明结构体的同时定义一个结构体变量
//定义结构体变量
struct Stu s2; //定义一个结构体变量s,不初始化。
struct Stu s3 = { "zhangsan", 18, "男" }; //定义一个结构体变量s3,并且初始化
//声明一个结构体,结构体的成员的类型是另一个结构体类型
struct Person
{
int num;
struct Stu s;
}p1 = { 15,{"zhangsan" ,25, "男"}}; //声明结构体的同时定义一个结构体变量p1并且初始化
//定义结构体变量,结构体嵌套初始化
struct Person p2 = { 100,"lisi",18,"女" }; //这里的struct Stu s成员初始化时可以加{},也可以不用加
结构体定义变量的方式有很多种,根据自己喜欢的方式去定义变量。
三、结构体的成员访问
我们学习了结构体变量的定义以及初始化,那我们如何通过结构体变量去访问结构体内的成员呢?
在C语言中,访问结构体成员的方式有两种,一是,通过'.'操作符进行访问,二是通过'->'操作符访问。这个两个操作符也在前面的章节学习过。C语言的所有操作符系列,操作符给操作数找对象-优快云博客
这两个操作符使用的对象不同,一个是使用在结构体变量上,一个是使用在结构体指针变量上。
1、使用‘.’操作符访问结构体成员
struct Stu
{
char name[20];
int age;
char sex[5];
};
struct Stu s1 = { "zhangsan", 18, "男" };
printf("姓名:%s\t年龄:%d\t性别:%s\n",s1.name,s1.age,s1.sex);
2、使用‘->’操作符访问结构体成员
struct Stu
{
char name[20];
int age;
char sex[5];
};
struct Stu s1 = { "lisi", 20, "男"};
struct Stu* s = &s1;
printf("姓名:%s\t年龄:%d\t性别:%s\n", s->name, s->age, s->sex);
四、结构体传参
结构体的基本知识点已经学得差不多了,现在就学习一下结果作为函数参数时如何使用。
struct Stu
{
char name[20];
int age;
char sex[5];
};
void printStruct1(struct Stu s)
{
printf("姓名:%s\t年龄:%d\t性别:%s\n", s.name, s.age, s.sex);
}
void printStruct2(struct Stu *s)
{
printf("姓名:%s\t年龄:%d\t性别:%s\n", s->name, s->age, s->sex);
}
int main()
{
struct Stu s1 = { "wangwu", 16, "男" };
printStruct1(s1);
printStruct2(&s1);
return 0;
}
代码中的printStruct1和printStruct2函数都是打印结构体成员的值,唯一的差别就是函数的形参不一样,一个是传值,一个是传址,那这两个有什么区别呢?
传值调用:把实参的值全部拷贝一份给形参,内存中这时就会有两份一样的数据。
传址调用:把实参的地址传给形参,内存中这时会开辟一个指针变量,指向实参的地址。
函数传参的时候,参数需要压栈,如果一个结构体很大,传值调用时,参数压栈的系统开销比较大,而且也比较占内存,所以会导致系统性能下降。传址调用时,参数压栈只会压栈一个地址,而且内存占用也比较少,因为不管结构体多大,形参都只会在内存中开辟8字节大小的指针来存放实参的地址。
所以在这里建议铁子们,在对结构体传参的时候,尽量使用传址调用。
在这里给铁子们补充一个小小的知识点,结构体可以结合typedef关键字,这样结合使用的时候更加方便。
int main()
{
typedef struct Person
{
char name[20];
int age;
}person;
person p1 = { "tom",20 };
printf("%s\t%d\n",p1.name,p1.age);
return 0;
}
typedef关键字的作用就是对数据类型进行重命名。typedef关键字加在结构体前面表示对这个结构体类型重新命名为person,如果后面需要定义这个结构体变量时,就是直接使用person去定义就行了。这样是不是就很方便了。
总结
结构体这章节就结束了,后面会写一篇自定义数据类型的内容,敬请期待。本章学习了结构体如何定义以及初始化,如果是结构体变量和结构体指针变量,我们通过哪两种方式去访问,是不是通过.和->两个操作符去访问。最后一个点就是结构体有不同的方式可以作为函数参数,那哪种方式更好呢。
铁子们一起加油哇~
谢谢铁子们