C的实用笔记38——结构体的引入和定义
1.为什么要用结构体?
0、原因:实际开发中,我们需要将不同类型的数据组合成一个整体,这就是结构体。结构体是自创的类型。
1、查找一名学生信息的两种方案:在EXCEL表格和数据库中经常有这种情况,比方说一个学生的信息可能包括:学号、姓名、性别、年龄、成绩、地址等。现在我们有两种方案来查找任意一名学生的信息,如图:
- 方案一:以行为一个整体(结构体),不用看其他行就能读取一个学生的所有信息。
- 方案二:以列为一个整体(数组),需要先按列查找(比方说先找学生学号),然后记住行号,需要看所有列才能读取一个学生的所有信息。
2.结构体变量的四要素
与普通变量的四要素完全相同。
1、结构体变量的类型:也就是结构体,它是我们自创的类型,简称构造类型。它的声明通常不放在函数中,书写的方式就像全局变量,因为它要尽可能让程序中的所有位置都能使用这个类型声明。结构体又有三部分:
- struct关键字:表示构造的是结构体。
- 结构体类型名:编程习惯是用大写开头,小写开头虽然不出错,就是看起来太low了。
- 结构体成员列表:成员列表也称为域表,通常我们称结构体成员列表(域表)中的每个成员为成员变量(域),成员变量之间用分号隔开。你可以定义许多成员变量,但并不是每一个选项在具体使用中会被派上用场,不要给成员变量赋值,虽然不出错,但是看起来太low了。成员列表中的成员变量可以是我们之前学过的任何类型的变量,比如整型、字符型、字符数组、各类指针、浮点型。甚至可以是结构体类型的成员变量。当然,成员列表中的变量可以是同一类型的,这时结构体看起来就像数组一样。
struct Student //struct是关键字,Student是自己取的结构体类型名 { //花括号中的是结构体成员列表int num;char name[32];char sex;int age;double score;char addr[50]; }; //从此以后,我们构造了一个结构体,它是 struct Student 类型。
1、结构体的知识点:
- 结构体声明时,末尾加分号;
- 结构体这个构造类型,决定了结构体变量占用空间的大小,系统会在程序运行或编译阶段给你静态分配好内存。这个类型占用多少内存当然需要用sizeof来测一下,留在第2小节(结构体内存分配)中讲。
- 与int a; 中 类型名是int一个道理,这里struct Student 在概念上就相当于 int。
2、结构体变量的名字:是结构体变量定义时候的名字,与 int a; 中变量名是a一个道理,留在本节第3部分讲
3、结构体变量的地址:显然这就是指向结构体变量的指针,留在第4小节(结构体指针)中讲
4、结构体变量的值:这里指的是结构体变量中成员变量的值,留在本节第4、5、6部分讲
3.结构体变量的定义
1、标准的定义方式:结构体声明和结构体变量定义分开写。
- 由于结构体是自定义的构造类型,所以需要先声明结构体,然后拿它来定义结构体变量。
#include <stdio.h> struct Student {int num;char name[32];char sex;int age;double score;char addr[50]; }; int main(int argc, char const *argv[]) {struct Student stu1; //stu1就是struct Student类型的结构体变量 }
2、见怪不怪的定义方式:
- 声明结构体,同时定义结构体变量:后面照样可以定义其他结构体变量,但这个方法尽量少用
#include <stdio.h> struct Student {int num;char name[32];char sex;int age;double score;char addr[50]; } stu2, stu3; //尽量少用 int main(int argc, char const *argv[]) {struct Student stu1; }
- 声明结构体时不写类型名,必须同时定义结构体变量:少用,因为后面无法再拿它来定义其他结构体变量
#include <stdio.h> struct //不写结构体类型名 {int num;char name[32];char sex;int age;double score;char addr[50]; } stu2, stu3; //同时在这里定义结构体变量,不要使用这种方法
4.结构体变量中有许多成员变量,如何引用?
数组引用数组元素的方式有:数组下标法、数组名偏移后取星花。但是这些明显都不适用于结构体。
1、用点运算符来访问结构体变量中的成员变量(域):
- 单级引用(成员列表中没有构造类型变量):结构体变量名.成员变量名
#include <stdio.h> #include <string.h> struct Student {int num;char name[32];char sex;int age;double score;char addr[50]; }; int main(int argc, char const *argv[]) {struct Student stu1; stu1.num = 64031; //点运算符访问结构体变量中的成员变量strcpy(stu1.name, "Li Hua");stu1.sex = 'M'; stu1.age = 24;stu1.score = 94;strcpy(stu1.addr, "杭州");printf("学号:%d,名字:%s,性别:%c,年龄:%d,分数:%lf,地址:%s\\n", \\stu1.num, stu1.name, stu1.sex, stu1.age, stu1.score, stu1.addr);return 0; }
- 二级引用(成员列表中有结构体变量):结构体变量名.成员变量名.成员变量名
#include <stdio.h> #include <string.h> struct Day {int year;int month;int day; }; struct Student {int num;char name[32];char sex;int age;double score;char addr[50];struct Day birth; //结构体的成员列表中还有结构体变量 }; int main(int argc, char const *argv[]) {struct Student stu1; stu1.num = 64031; strcpy(stu1.name, "Li Hua");stu1.sex = 'M'; stu1.age = 24;stu1.score = 94;strcpy(stu1.addr, "杭州");stu1.birth.year = 1999; //点运算符二级引用stu1.birth.month = 12;stu1.birth.day = 1;printf("学号:%d,名字:%s,性别:%c,年龄:%d,分数:%lf,地址:%s,生日:%d年%d月%d日\\n", \\stu1.num, stu1.name, stu1.sex, stu1.age, stu1.score, stu1.addr, \\stu1.birth.year, stu1.birth.month, stu1.birth.day);return 0; }
5.结构体变量的初始化
结构体变量的初始化和数组的初始化方法几乎一模一样,也分为全部初始化和部分初始化,都是用花括号来实现。
1、全部初始化:定义结构体变量时用花括号赋值,花括号内的数据与结构体成员列表一一对应,数据用逗号分隔。
#include <stdio.h>
//#include <string.h> 由于是初始化,就不需要用strcpy修改字符串
struct Student
{int num;char name[32];char sex;int age;double score;char addr[50];
};
int main(int argc, char const *argv[])
{struct Student stu2 = {64066,"Li Fang",'M',24,90,"大连"}; //结构体变量的全部初始化printf("学号:%d,名字:%s,性别:%c,年龄:%d,分数:%lf,地址:%s", \\stu2.num, stu2.name, stu2.sex, stu2.age, stu2.score, stu2.addr);return 0;
}
2、部分初始化:只能按照顺序给结构体变量的前几个成员变量初始化,不允许用空格跳过中间某个变量
#include <stdio.h>
//#include <string.h> 由于是初始化,就不需要用strcpy修改字符串
struct Student
{int num;char name[32];char sex;int age;double score;char addr[50];
};
int main(int argc, char const *argv[])
{struct Student stu2 = {64066,"Li Fang",'M',24,}; //结构体变量的部分初始化printf("学号:%d,名字:%s,性别:%c,年龄:%d,分数:%lf,地址:%s", \\stu2.num, stu2.name, stu2.sex, stu2.age, stu2.score, stu2.addr);return 0;
}
6.4和5中哪一种方法确定结构体变量的值比较好?
1、需要分情况:看起来好像定义结构体变量时就初始化比较简单,但是要分情况,因为有的时候一开始没法确定结构体变量中成员变量的值,就是需要通过点运算符来进行访问。
7.结构体变量相互赋值的条件
1、知识点:总的来说就是结构体相同,也就是结构体变量的类型相同
- 结构体类型名一致
- 结构体成员列表一致
8.习题
习题1:输入两个学生的信息,找出成绩好的学生,并显示他的信息。
- 思路:
构造一个与学生信息有关的结构体类型1: struct Student{......}; 1. 用构造体类型1,定义两个结构体变量stu1和stu2,初始化或者通过点运算符确认结构体变量的值 2. 定义一个与stu1和stu2相同类型的结构体变量max,它表示成绩好的同学,暂时认为stu1成绩好: struct Student max = stu1; 3. 判断,stu1.score是否小于stu2.score,3.1 如果是,那么,认为stu2是成绩好的同学: max = stu2; 4. 打印max同学的信息
- 代码:
#include <stdio.h> #include <string.h> struct Student {int num;char name[32];char sex;int age;double score;char addr[50]; }; int main(int argc, char const *argv[]) {struct Student stu1; struct Student stu2 = {64066,"Li Fang",'M',24,90,"大连"};struct Student max;stu1.num = 64031; strcpy(stu1.name, "Li Hua");stu1.sex = 'M'; stu1.age = 24;printf("请输入%s的成绩:\\n", stu1.name);scanf("%lf", &stu1.score);strcpy(stu1.addr, "杭州");max = stu1;if(stu1.score < stu2.score){max = stu2;}printf("成绩比较好的是:\\n");printf("学号:%d,名字:%s,年龄:%d,分数:%lf,地址:%s\\n", \\max.num, max.name, max.age, max.score, max.addr);return 0; }