李祥 E-mail:tom_lx@126.com QQ:100756
第十章 用户自定义数据类型 目录 1 2 3 4 5 6 7 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组 共用体数据类型 6 枚举数据类型 7 用typedef定义数据类型
知识点要求: 技能要求: 教学要求 1 结构体数组的定义和引用 2 3 1 2 结构体的定义和变量的使用 共用体的定义和变量的使用 掌握结构体数组在程序设计中的应用 2 区分结构体和共用体
10.1 学生信息管理系统的开发 任务描述: 开发一个简单的学生信息管理系统,实现学生基本信息的录入、查询、修改、删除等功能。 任务要求: (1)设计一个菜单界面。(已学) (2)编写inputInfo函数,实现学生信息的录入。 (3)编写findInfo函数,按用户需求查找学生信息。 (4)编写updateInfo函数,按用户需求修改学生信息。 (5)编写deleteInfo函数,删除指定学生信息。
10.1 学生信息管理系统的开发 任务分析: (1)学生基本信息包括学号、姓名、性别、年龄、地址等信息。 (2)实现本系统需要解决的两个关键问题: 首先,如何构建用于存放学生信息记录的数据类型; 其次,如何运用构建的新数据类型定义变量及数组,从而存储学生记录信息 (3)所有对学生信息的管理其实就是对结构体数组元素进行处理。
10.1 学生信息管理系统的开发 涉及知识点 结体类型的定义 结构体变量的使用 结构体数组定义及引用 结构体数据组元素的查找、修改、删除等操作
10.2 结构体数据类型概述 有时需要将不同类型的数据组合成一个有机的整体。例如,一个学生的学号、姓名、性别、年龄、成绩、家庭地址等项,这些项都与某一学生有联系,对每个学生来说,除了其各项的值不同外,表示形式是一样的。
10.2 结构体数据类型概述 用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体。 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };//注意分号不能少 由程序设计者指定了一个结构体类型struct student 它包括num,name,sex,age,score,addr等不同类型的成员
10.2 结构体数据类型概述 定义一个结构体类型的一般形式为: struct 结构体名 { 类型标识符 成员1名字; { 类型标识符 成员1名字; 类型标识符 成员2名字; 类型标识符 成员3名字; … }; 其中,“{”和“}”之间的内容被称为成员表列。
10.3 结构体变量的使用 10.3.1 结构体变量的定义 前面只是建立了一个结构体类型,它相当于一个模型,并没有定义变量,其中并无具体数据,系统对之也不分配存储单元。 为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。 要定义一个结构体类型的变量,可以采取以下三种方法。
10.3 结构体变量的使用 结构体类型名 结构体变量名 1. 先定义结构体类型,再定义该类型变量 前面已定义了一个构体类型struct student,可以用它来定义变量 struct student student1,student2; 结构体类型名 结构体变量名
10.3 结构体变量的使用 2.在定义类型的同时定义变量 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1,student2;
10.3 结构体变量的使用 3. 不指定类型名而直接定义结构体类型变量 其一般形式为: struct { 成员表列 }变量名表列; 即不出现结构体名。
10.3 结构体变量的使用 说明: 结构体类型与结构体变量是不同的概念。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。 (2) 对结构体变量中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。
10.3 结构体变量的使用 (3) 成员可以属于另一个结构体类型。 struct date { int month; int day; int year; }; struct Stu { int num;char name[20]; char sex;int age; struct date birthday; char addr[30]; };
10.3 结构体变量的使用 (4)成员名可以与程序中的变量名相同,二者不代表同一对象。例如,程序中可以定义一个变量num,它与struct student中的num是两回事,互不干扰。
10.3 结构体变量的使用 10.2.2 结构体变量的引用 引用结构体变量应遵守以下规则: (1)不能将一个结构体变量作为一个整体进行输入和输出。 只能对结构体变量中的各个成员分别输入和输出。引用方式为: 结构体变量名.成员名 (2)结构体变量可以通过赋值运算符将其值赋给另一个相同类型的结构体变量,实现结构体变量中所有成员内容的复制。 网工 12.16
10.3 结构体变量的使用 struct date { int month; int day; int year; }; struct Stu { int num;char name[20]; char sex;int age; struct date birthday; char addr[30]; }student1,student2; (3)如果成员本身又属一个结构体类型,则要用若干级成员运算符,一级一级地找到最低一级的成员。只能对最低级的成员进行赋值或存取以及运算。 student2=student1; student1.birthday.month
10.3 结构体变量的使用 10.2.3 结构体变量的初始化 【例10.1】定义学生结构体类型student和两个student类型的变量student1和student2,对其初始化,并在主函数main中输出student1和student2。 解题思路:该题主要考察对结构体类型的定义和使用,包括结构体变量的初始化、赋值和输出,其中关键是如何访问结构体变量的成员。
#include <stdio.h> #include <string.h> struct date{int month;int day;int year;}; struct student {int num; char name[20]; char sex; date birthday; char addr[30]; }student1={89031,"Li Lin",'M',2,3,1993,"123 Beijing Road"},student2; void main() {printf("学号\t姓名\t性别\t出生日期\t家庭住址\n"); printf("%d\t%s\t%c\t%d-%d-%d\t%s\n", student1.num,student1.name,student1.sex, student1.birthday.month,student1.birthday.day, student1.birthday.year,student1.addr);
student2=student1; student2.num=89032; strcpy(student2.name,"Liu Lin"); printf("%d\t%s\t%c\t%d-%d-%d\t%s\n", student2.num,student2.name,student2.sex, student2.birthday.month,student2.birthday.day, student2.birthday.year,student2.addr); }
10.4 结构体数组 10.4.1 结构体数组的定义 和定义结构体变量的方法相同,只需说明其为数组,可采用下列3种方法中的一种。 (1) struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; student stu[3];
10.4 结构体数组 (2) struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu[3]; (3) struct { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu[3];
10.4 结构体数组 以上定义了一个数组,数组名为stu, 有3个元素,每个元素为student类型数据
数组各元素在内存中连续存放。
10.4 结构体数组 10.4.2 结构体数组的初始化 结构体数组可以初始化,形式类似多维数组。 struct student { int num; char name[20]; char sex; int age; float score; char add[30]; }stu[3]={{10101,"Li Lin",'M',18,86,"103 Beijing Road"}, {10102,"Zhang Fan",'M',19,92,"130 Shanghai Road"}, {10103, "Wang Min",'F',17,80.5,"109 Zhongshan Road"}};
10.4 结构体数组 10.4.3 结构体数组的引用 结构体数组的引用完全类似于结构体变量的引用,只是用结构体数组元素来代替结构体变量,其他规则不变。 stu[0].num //引用某一数组元素的成员 stu[0].name//引用某一数组元素的成员 stu[2]=stu[1]//将结构体数组元素作为一个整体
10.4 结构体数组 【例10.2】统计候选人得票数的程序。设有3个候选人,每次输入1个得票的候选人的名字,要求最后输出各个候选人的得票结果。 解题思路: (1)定义候选人结构体,包括候选人姓名和得票数两个成员; (2)定义有三个候选人的结构体数组,并初始化候选人信息; (3)在主函数main中输入候选人名字,与候选人结构体数组中的候选人名字匹配,将匹配上的候选人名字对应的选票数加1;对所有的选民循环匹配。
#include<stdio.h> #include<string.h> struct person { char name[20]; int count; }leader[3]={"Li",0,"Zhang",0,"Wang",0}; void main() { int i,j; char leader_name[20]; printf("共10个选民\n请输入您选择的候选人姓名:\n"); for (i=1; i<=10; i++) { scanf("%s",leader_name); for (j=0; j<3; j++) if (strcmp (leader_name,leader[j].name)==0)leader[j].count++; } printf("选举结果如下:\n"); for (i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count); return;
10.4 结构体数组 练习 完成学生信息管理系统的开发。 提示: (1)根据用户不同的需要,学生信息查找可以有多种不同的方式,用户可以按照学号、姓名等进行查询。 (2)学生信息记录保存在结构体数组中,用户查找记录的过程实际上是遍历数组,并将当前记录与查找条件匹配的过程。 (3)学生信息的修改、删除等操作,需先找到该学生信息,再对对应的数组元素进行处理。
10.5 共用体数据类型 10.5.1 共用体的概念 需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构称为共用体。
10.5 共用体数据类型 union data { int i; char ch; float f; } a, b, c; (1) union 共用体名 { 成员表列; }变量名表列; union data { int i; char ch; float f; } a, b, c;
10.5 共用体数据类型 (2) union data { int i; char ch; float f; } ; data a, b, c; (3) union { int i; char ch; float f; } a, b, c;
10.5 共用体数据类型 注意区分共用体和结构体: “共用体”:各成员占相同的起始地址,所占内存长度等于最长的成员所占内存。 “结构体”:各成员占不同的地址,所占内存长度等于全部成员所占内存之和。
10.5 共用体数据类型 只有先定义了共用体变量才能引用它。 例如,前面定义了a、b、c为共用体变量 下面的引用方式是正确的: a.i //引用共用体变量中的整型变量i a.ch //引用共用体变量中的字符变量ch a.f //引用共用体变量中的实型变量f
10.5 共用体数据类型 10.5.2 共用体变量的引用方式 同结构体类型变量一样,不能直接输入和输出共用体类型变量,输入输出时用共用体变量的成员。 例如: printf(″%d″, a); //不能将共用体变量整体输出 应该写成 printf(″%d″, a.i)或printf(″%c″, a.ch) 但允许同类型的共用体变量之间赋值。 例如:b=a;
10.5 共用体数据类型 10.5.3共用体类型数据的特点和应用 在使用共用体类型数据时要注意以下一些特点: (1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。 (2)共用体变量中起作用的成员是最后一次赋值的成员。
10.5 共用体数据类型 例:有以下共用体 在完成以上三个赋值运算以后,只有a.f是有效的,a.i和a.ch已无意义了 union data { int i; char ch; float f; } ; data a; a.i=1; a.ch=’a’; a.f=1.5; 在完成以上三个赋值运算以后,只有a.f是有效的,a.i和a.ch已无意义了
10.5 共用体数据类型 (3)不能企图引用变量名来得到成员的值;可以对共用体变量初始化,但初始化表中只能有一个常量。 例如,下面这些都是不对的: ① union { int i; char ch; float f; } a={1, 'a', 1.5}; a=1; int m;m=a; 错:不能初始化全部成员,初始化表只能有一个常量 错:不能对共用体变量赋值,但允许共用体变量互相赋值 错:不能引用共用体变量名以得到值
10.5 共用体数据类型 【例10.3】设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。现要求把它们放在同一表格中,见图10.8。如果“Job”项为“S”(学生),则第5项为class(班)。即Li是501班的。如果“Job”项是“T”(教师),则第5项为position(职务)。Wang是prof(教授)。
10.5 共用体数据类型 解题思路:可以看出,学生和教师所包含的数据是不全相同的,所以建立人员结构体,包括姓名、号码、性别、职业和分类。其中,分类由职业决定,用共用体来处理即将class和position放在同一段内存中,也就是说,结构体中的“分类”成员是一个共用体类型。根据题目要求绘制的程序流程图如图10.9所示,程序主要由循环输入和循环输出两部分构成。
10.5 共用体数据类型
10.5 共用体数据类型
10.5 共用体数据类型 思考题:如果将循环输入和循环输出的功能分别编写输入函数input和输出函数output,主函数main通过调用输入和输出函数,程序该如何实现?
10.6 枚举数据类型 如果一个变量只有几种可能的值,可以定义为枚举类型。 所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
10.6 枚举数据类型 定义枚举类型用enum开头。例如: enum weekday {sun, mon, tue, wed, thu, fri, sat}; 定义了一个枚举类型enum weekday,可以用此类型来定义变量。例如: enum weekday workday, week_end; workday和week_end被定义为枚举变量,它们的值只能是sun到sat之一。例如: workday=mon; week_end=sun;
10.6 枚举数据类型 也可以直接定义枚举变量,如: enum {sun, mon, tue, wed, thu, fri, sat}workday, week_end; 其中sun、mon、…、sat等称为枚举元素或枚举常量,它们是用户定义的标识符。
10.6 枚举数据类型 说明: (1)在C编译中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。 例如: sun=0; mon=1; 是错误的。
10.6 枚举数据类型 (2)枚举元素作为常量是有值的,C语言编译按定义时的顺序使它们的值为0, 1, 2, …。在上面定义中,sun的值为0,mon的值为1,……,sat为6,如果有赋值语句: workday=mon; workday变量的值为1,这个整数是可以输出的。如: printf(″%d″, workday); 将输出整数1。 也可以改变枚举元素的值,在定义时由程序员指定,如: enum weekday {sun=7, mon=1, tue, wed, thu, fri, sat}workday, week_end; 定义sun为7,mon=1,以后顺序加1,sat为6。
10.6 枚举数据类型 (3)枚举值可以用来作比较判断。 if (workday==mon) … if (workday>sun) … 枚举值的比较规则是:按其在定义时的顺序号比较。 (4)一个整数不能直接赋给一个枚举变量。 workday=2; 错 它们属于不同的类型。应先进行强制类型转换才能赋值。如: workday=(enum weekday)2
10.7 用typedef定义数据类型 除了可以直接使用C提供的标准类型名(如int、char、float、double、long等)和自己定义的结构体、共用体、枚举类型外,还可以用typedef定义新的类型名来代替已有的类型名。如: typedef int INTEGER; typedef float REAL; 指定用INTEGER代表int类型,REAL代表float。 这样,以下两行等价: int i, j; float a, b; INTEGER i, j; REAL a, b; 13-15 12.19
10.7 用typedef定义数据类型 可以定义结构体类型: typedef struct { int month; int day; int year; } DATE; 定义新类型名DATE,它代表上面定义的一个结构体类型。这时就可以用DATE定义变量: DATE birthday; 注意:不要写成struct DATE birthday;
10.7 用typedef定义数据类型 还可以进一步: (1)typedef int NUM[100]; //定义NUM为整型数组类型 (2)typedef char *STRING; //定义STRING为字符指针类型 STRING p, s[10]; //p为字符指针变量,s为指针数组 (3)typedef int ( * POINTER)() //定义POINTER为指向函数的指针类型 POINTER p1, p2; //p1、p2为POINTER类型的指针变量
10.7 用typedef定义数据类型 归纳起来,定义一个新的类型名的方法是: (1)先按定义变量的方法写出定义体,如: int i; (2)将变量名换成新类型名,如: int COUNT; (3)在最前面加typedef,如: typedef int COUNT; (4)然后可以用新类型名去定义变量。
10.7 用typedef定义数据类型 再以定义数组类型为例来说明: (1)先按定义数组变量形式书写: int n[100]; int NUM[100]; (3)在前面加上typedef: typedef int NUM[100]; (4)用来定义变量: NUM n;
10.7 用typedef定义数据类型 说明: (1)用typedef可以定义各种类型名,但不能用来定义变量。 (3)当不同源文件中用到同一类型数据时,常用typedef定义一些数据类型,把它们单独放在一个头文件中,然后在需要用到它们的文件中用#include命令把头文件包含进来。 (4)使用typedef有利于程序的通用与移植。
重点: 难点: 本章小结 1 2 3 1 2 结构体的概念及定义 共用体的概念及定义 结构体数组的定义及引用 结构体数组的应用 共用体类型的应用
本章结束!