为什么需要结构体?
💫首先,来举一个例子看一下为什么需要结构体。
在学籍管理系统中,要存储一个班级所有学生的信息,包括,姓名、性别、学号、年龄、成绩等等好几项数据,而且这些数据之间是有内在联系的,他们是一个整体,是用来表示一个学生的信息。如果把它们定义成相互独立的变量,就无法体现它们之间的内在联系:
char name[20];//姓名 char sex;//性别 int num;//学号 int age;//年龄 int score;//成绩
而由于每一项的数据类型不同,也无法放到数组中,因为数组中个元素的类型必须一致。
如果能定义一个变量,而这个变量正好包含这六项,即把它们合并成一个整体的话就好了。因此,C语言中提供了结构体类型。结构体,是将不同类型的数据按照一定的功能需求进行整体封装,封装的数据类型的和大小均可以由用户指定。
结构体类型的定义
结构体类型定义的一般形式为:
struct 结构体类型名 { 成员列表 };
即:
struct 结构类型名 { 类型说明符 成员名1; 类型说明符 成员名2; …… 类型说明符 成员名n; };
例如将学生的信息定义为结构体:
struct STUDENT { char name[20]; char sex; int num; int age; int score; };//最后的分号千万不要忘记
💫说明:
(1)strcut是声明结构体类型时必须使用的关键字,不能省略。结构体这个词是根据英文字母strcuture翻译而来的。
(2)结构体数据类型是由一些基本数据类型组合而成的新的数据类型。结构体类型中的成员是人为定义的,所以结构体类型是我们认为定义的数据类型。
(3)‘{}’内是该结构体包含的各个成员,类型说明符来说明每个成员的类型,它们必须是有效的数据类型,比如说int、char、float、double、指针、数组等等。
(4)注意,最后‘{}’后面的分号千万不能省略。
(5)以上例子中的结构体为例,strcut STUDENT是定义的数据类型的名字,它向编译系统声明,这是一个结构体类型,包括name、sex、num、age、grade这些成员。
(6)声明结构体类型仅仅是声明了一个结构体类型,系统并不会为之分配内存,就如同编译系统不会为int分配内存。只有当使用的这个类型定义了变量,系统才会为变量分配内存。
结构体变量
💫再次搞清楚结构体类型与结构体变量的区别
(1)以struct STUDENT为例,这仅仅是一个类型说明符,而不是变量名,它与int、float、double等等仅仅是一个类型名,系统并不会·为此分配内存空间。
(2)结构体类型与int、double、float等基本数据类型所不同的是,这些基本数据类型都是C语言中已经定义好的,可以直接使用,而结构体数据类型需要根据实际问题自己构造。如果程序中想要使用结构体变量,就必须先构造该结构体变量,然后再定义该类型的变量。
结构体变量的定义
🌟方法一
先定义结构体类型,再定义结构体类型变量。
一般形式为:
struct 结构体类型名 结构体变量名表列;
例如,定义结构体类型 struct student,就可以使用该类型定义结构体变量,例如:
struct student student1,student2;
然后系统为变量student1和student2分配内存,分配内存空间时,按照结构结构体类型struct student所描述的数据组织形式进行内存空间的分配,结构体变量中的各个成员按定义结构体类型的书写顺序连续存放。
一般用这种方法比较多。
🌟方法二
在定义结构体变量的时候定义结构体变量。
一般形式为:
struct 结构体类型名 { 类型说明符 成员名1; 类型说明符 成员名2; …… 类型说明符 成员名n; }结构体变量名表列;
在定义结构体变量的时候定义结构体变量这种方法,如果我们是在所有函数之前声明结构体类型,这时定义的变量就会成为全局变量。如果我们只是在某个函数中声明定义结构体类型,那么我们就只能在这个函数体内使用这种结构体类型。在其他的函数中除非再次声明,否则不能使用。而我们希望在很多情况下我们定义了一种结构体类型,就如同一些基本类型int、double、float等等一样在所有函数中都可以使用。所以这种方法使用的时候会有点纠结。
🌟方法三
直接定义结构体类型的变量
一般形式为:
struct //无名结构体 { int num; char name[10]; char sex; int age; int score; }stu1,stu2;
这种定义方法省去了结构体类型名,该结构体仅能使用一次。直接定义结构体变量是一次性的。
结构体变量的引用
结构体变量是由若干个不同类型的数据成员组成的集合。所以结构体变量不能整体引用,只能一个成员一个成员地进行引用。
⭐️一般对结构体地使用,不仅仅是引用,包括赋值、输入、输出以及其他运算等都是通过结构体变量的成员来实现的。(类似于数组的使用)
结构体成员引用的一般形式如下:
结构体变量.成员名
“. ”是“成员运算符”,它在所有运算符中优先级最高,因此可以将student1.num作为一个整体来看待。
若先声明结构体类型:
struct student { int num; char name[10]; char sex; int age; int score; };
再在函数中定义结构体类型变量:
struct student stu1,stu2;
对结构体类型变量成员进行赋值:
stu1.age=18;// *age成员是整型变量,所以stu1.age和整型变量具有相同的性质 stu1.sex='M';//所赋的值即字符型变量 stu2.score=88;
结构体变量的初始化
结构体变量的初始化和一维数组的初始化类似,可以在定义的时候完成初始化,也可以在定义之后初始化。
一般情况下,都是在定义的时候完成初始化,因为如果在定义之后再初始化的话,就需要对结构体类型的变量的每个成员依次赋值,这样比较麻烦。
定义时初始化,将各个成员的初值用大括号“{}”括起来,括号内各初值的数据类型、顺序要和结构体类型中的成员一致,数据项之间用逗号隔开。
初始化时,按照左对应关系赋初值,如果初值的个数小于结构体中成员的个数,其余成员将自动初始化为0。
#include<stdio.h> struct student { char name[20]; char sex; int num; int age; int score; };//声明一种结构体类型 int main (void) { struct student stu1={"小明",'M',2208012,18,90}; //定义结构体类型变量并完成初始化 printf("name=%s\nsex=%c\nnum=%d\nage=%d\nscore=%d\n",stu1.name,stu1.sex,stu1.num,stu1.age,stu1.score); return 0; }
⭐️注意,同字符、字符数组的初始化一样,如果是字符,如 char sex,'M’就用单引号括起来。如果是字符串,如 char name ,"小明"就用双引号括起来。
结构体嵌套
结构体类型成员的类型也可以是结构体,即结构体类型定义可以是嵌套的。
再以学生信息为例,除了上面举例所提到的姓名、性别、学号、年龄、分数之外,还会有出生日期,这时候就会具体到年、月、日,会有家庭住址信息,具体到省、市、区、门牌号……
在学生信息中,出生日期和家庭地址也应该用结构体描述。
首先,定义 struct date结构体类型:
struct date { int year;//年 int month;//月 int day;//日 };
再定义 struct address结构体类型:
struct address { char city[50];//城市 -字符串 char street[50];街道-字符串 int streetnum;//门牌号 };
定义struct student结构体类型:
struct student { char name[20]; char sex; int age; int num; int score; struct date brithday;//成员brithday 的类型是struct date类型。 //brithday有自己的成员year、month、day struct address addr;//成员addr的类型是struct address类型。 //addr有自己的成员city、street、streetnum };
嵌套的结构体类型的变量中的结构体成员和同类型的结构体变量具备相同的性质。
引用时按照从左到右,从内到外的方式,用“.”运算一级一级地运算,直到找到最低一级的成员。
例如:
struct student stu1;//定义结构体类型变量 stu1.sex='M'; stu1.brithday.year=2004; stu1.brithday.month=1; stu1.brithday.day=12;
感谢小伙伴的阅读,欢迎指出错误交流呀🥰