第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型 第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型 学习方法建议: 结合第二章的数据类型,了解属于构造类型的结构体类型、共用体类型、枚举类型,比较它们的相同点和区别,通过例题掌握这些数据类型的定义和使用,并在此基础上掌握链表的应用。本章的难点是链表的应用。
10.1 引例 1.问题描述——构建手机通讯录 众所周知,手机中有一个简单的通讯录工具,用于管理联系人的基本信息,其基本功能包括对联系人信息的新建、修改、删除和查询等。 2.引例分析 要想构建手机通讯录,应创建联系人的基本信息,而联系人的基本信息应该包括姓名、年龄和联系电话等,假设通讯录最多容纳50名联系人的信息,建立一个数组friends,数组的大小为50,每一个数组元素都应存放姓名、年龄和联系电话等信息。
3.程序代码 #include<stdio.h> #include<string.h> struct friend_list /*手机通讯录结构体定义*/ { char name[10]; /*姓名*/ int age ; /*年龄*/ char telephone[13]; /*联系电话*/ }; main() { int choice; char name[10]; struct friend_list friends[50]; /*包含50个人的通讯录*/ do{ printf("手机通讯录功能选项:1:新建 2:修改 3:删除 4:查询0:退出\n"); printf( "请选择功能:"); scanf( "%d",&choice) ;
switch(choice) { case 1: printf("新建联系人姓名:"); ; /* new_friend(friends); */ break; case 2: printf("请输入要修改的联系人姓名:"); scanf("%s",name); ; /* modify_friend(friends,name); */ case 3: printf("请输入要删除的联系人姓名:"); ; /* delete_friend(friends,name); */ case 4: printf("请输入要查询的联系人姓名:"); ; /* search_friend(friends,name); */ case 0:break; } }while(choice!=0); printf("谢谢使用通信录功能!\n"); }
10.2 结构体类型及其变量 10.2.1 结构体类型与结构体变量的定义 结构体是一种构造数据类型 10.2 结构体类型及其变量 10.2.1 结构体类型与结构体变量的定义 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体-------自定义数据类型 1. 结构体类型定义 合法标识符 可省:无名结构体 struct 结构体名 { 类型标识符 成员名; ……………. }; 成员类型可以是 基本型或构造型 struct是关键字, 不能省略
… ….. 例 struct student { int num; char name[20]; char sex; int age; score addr 2字节 20字节 1字节 4字节 30字节 … ….. 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } ; 结构体类型定义描述结构 的组织形式,不分配内存 结构体类型定义的作用域
2.2 结构体类型变量定义 先定义结构体类型,再定义结构体变量 一般形式: 例 #define STUDENT struct student { 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; 例 #define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; float score; char addr[30]; }; STUDENT stu1,stu2; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2; 用宏定义一个符号常量来表示一个结构体类型名
定义结构体类型的同时定义结构体变量 一般形式: 例 struct student { int num; char name[20]; 类型标识符 成员名; ……………. }变量名表列; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;
直接定义结构体变量 一般形式: 例 struct { int num; char name[20]; char sex; int age; 用无名结构体直接定义 变量只能一次 struct { 类型标识符 成员名; ……………. }变量名表列; 例 struct { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;
说明 结构体类型与结构体变量概念不同 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体可嵌套 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体可嵌套 结构体成员名与程序中变量名可相同,不会混淆 结构体类型及变量的作用域与生存期 例 struct date { int month; int day; int year; }; struct student { int num; char name[20]; struct date birthday; }stu; num name birthday month day year 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu; num name birthday month day year
10.2.2 结构体变量的引用与初始化 引用规则 引用方式: 结构体变量名.成员名 结构体变量不能整体引用,只能引用变量成员 引用方式: 结构体变量名.成员名 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1.num=10; stu1.score=85.5; stu1.score+=stu2.score; stu1.age++; 可以将一个结构体变量赋值给另一个结构体变量 结构体嵌套时逐级引用 成员(分量)运算符 优先级: 1 结合性:从左向右 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; printf(“%d,%s,%c,%d,%f,%s\n”,stu1); () stu1={101,“Wan Lin”,‘M’,19,87.5,“DaLian”}; () 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; if(stu1==stu2) …….. () 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu1,stu2; num name birthday month day year stu1.birthday.month=12; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu2=stu1; ( )
【例10.2】 利用例10.1中定义的结构体类型struct std_info,定义一个结构体变量student,用于存储和显示一个学生的基本情况。 #include"stdio.h" struct date /*定义并初始化一个外部结构体变量student */ { int year; int month; int day; }; struct std_info { char no[7]; char name[9]; char sex[3]; struct date birthday; struct std_info student={"000102","张三","男",{1980,9,20}};
main() { printf("No: %s\n",student.no); /*引用student中的no成员项*/ printf("Name: %s\n",student.name); /*引用student中的name成员项*/ printf("Sex: %s\n",student.sex); /*引用student中的sex成员项*/ printf("Birthday: "); printf("%d- ", student.birthday.year); /*引用student中birthday的year成员项*/ printf("%d- ",student.birthday.month); /*引用birthday的month成员项*/ printf("%d\n", student.birthday.day); /*引用student中birthday的day成员项*/ }
结构体变量的初始化 形式一: 例 struct student { int num; char name[20]; char sex; 类型标识符 成员名; ……………. }; struct 结构体名 结构体变量={初始数据}; 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }; struct student stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
形式二: 例 struct student { int num; char name[20]; char sex; int age; 类型标识符 成员名; ……………. }结构体变量={初始数据}; 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
形式三: 例 struct { int num; char name[20]; char sex; int age; 类型标识符 成员名; ……………. }结构体变量={初始数据}; 例 struct { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
10.3 结构体数组 结构体数组的定义 三种形式: 形式一: struct student { int num; 形式二: 10.3 结构体数组 结构体数组的定义 三种形式: num name sex age stu[0] stu[1] 29B 形式一: struct student { int num; char name[20]; char sex; int age; }; struct student stu[2]; 形式二: struct student { int num; char name[20]; char sex; int age; }stu[2]; 形式三: struct { int num; char name[20]; char sex; int age; }stu[2];
strcpy(stu[0].name,”ZhaoDa”); 结构体数组初始化 结构体数组引用 分行初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[ ]={{100,“Wang Lin”,‘M’,20}, {101,“Li Gang”,‘M’,19}, {110,“Liu Yan”,‘F’,19}}; 全部初始化时维数可省 顺序初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[ ]={100,“Wang Lin”,‘M’,20, 101,“Li Gang”,‘M’,19, 110,“Liu Yan”,‘F’,19}; 引用方式: 结构体数组名[下标].成员名 例 struct student { int num; char name[20]; char sex; int age; }stu[ ]={{……},{……},{……}}; 例 struct { int num; char name[20]; char sex; int age; }stu[ ]={{……},{……},{……}}; struct student { int num; char name[20]; char sex; int age; }str[3]; stu[1].age++; strcpy(stu[0].name,”ZhaoDa”);
例3 计算学生的平均成绩和不及格的人数。 #include <stdio.h> struct student { int num; char *name; char sex; float score; } boy[5]={{101, "Li ping", 'M', 45}, {102, "Zhang ping", 'M', 62.5}, {103, "He fang", 'F', 92.5}, {104, "Cheng ling", 'F', 87}, {105, "Wang ming", 'M', 58} }; void main() { int i, count=0; float sum=0; for (i=0; i<5; i++) { sum+=boy[i].score; if (boy[i].score<60) count++; } printf("average=%f, count=%d\n", sum/5, count);
例4 统计候选人选票 #include <stdio.h> #include<string.h> 例4 统计候选人选票 #include <stdio.h> #include<string.h> struct person { char name[20]; int count;}leader[3]={"Li",0,"Zhang",0,"Wang",0}; main() { int i,j; char leader_name[20]; 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++; } for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count); name count Li Zhang Wang
10.4 指向结构体类型数据的指针 10.4.1 指向结构体变量的指针 定义形式:struct 结构体名 *结构体指针名; 10.4 指向结构体类型数据的指针 10.4.1 指向结构体变量的指针 定义形式:struct 结构体名 *结构体指针名; 例 struct student *p; #include <stdio.h> #include<string.h> main() { struct student {long int num; char name[20]; char sex; float score; }stu_1,*p; p=&stu_1; stu_1.num=89101; strcpy(stu_1.name,"Li Lin"); p->sex='M'; p->score=89.5; printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n", (*p).num,p->name,stu_1.sex,p->score);} 使用结构体指针变量引用成员形式 num name sex age stu p struct student { int num; char name[20]; char sex; int age; }stu; struct student *p=&stu; 存放结构体变量在内存的起始地址 (*结构体指针名).成员名 结构体指针名->成员名 结构体变量名.成员名 例 int n; int *p=&n; *p=10; n=10 struct student stu1; struct student *p=&stu1; stu1.num=101; (*p).num=101 例 指向结构体的指针变量 指向运算符 优先级: 1 结合方向:从左向右
10.4.2 指向结构体数组的指针 例 指向结构体数组的指针 struct student { int num; 10.4.2 指向结构体数组的指针 例 指向结构体数组的指针 num name sex age stu[0] p stu[1] stu[2] p+1 struct student { int num; char name[20]; char sex; int age; }stu[3]={{10101,"Li Lin",'M',18}, {10102,"Zhang Fun",'M',19}, {10104,"Wang Min",'F',20}}; main() { struct student *p; for(p=stu;p<stu+3;p++) printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age); }
* 结构体与函数 *.1 函数的结构体类型参数 用指向结构体的指针作函数参数 用结构体变量的成员作参数----值传递 用指向结构体变量或数组的指针作参数----地址传递 用结构体变量作参数----多值传递,效率低
例4.5 求某年某月某日是该年的第几天。 #include <stdio.h> struct ymd { int day; int month; int year; int dyear; }; int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int d_of_y(struct ymd *p) // 形参p为结构体指针变量 { int i, d; if(p->year%4==0&&p->year%100!=0||p->year%400==0) days[2]=29; else days[2]=28; d=p->day; //d的初值 for (i=1; i<p->month; i++) d=d+days[i]; return(d); /* 亦可以将d的值直接赋给p->dyear,实现返回 */ }
void main() { struct ymd date; // 定义结构体变量date while (1) printf("date(yyyy-mm-dd)=?(yyyy=0----Exit)\n"); scanf("%d-%d-%d", &date.year, &date.month, &date.day); if (date.year==0) break; date.dyear=d_of_y(&date); // 实参为结构体变量date的指针 printf("The days of the year is %d!\n", date.dyear); }
*.2 结构体类型的函数 例4.6 求下星期的今天是什么日期。 #include <stdio.h> struct ymd { *.2 结构体类型的函数 例4.6 求下星期的今天是什么日期。 #include <stdio.h> struct ymd { int day; int month; int year; }; int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; struct ymd date_nextweek(struct ymd d); // 对结构类型的函数进行声明 void main() { struct ymd whatdate, today; printf(Todays date(mm-dd-yyyy): ); scanf(%d-%d-%d, &today.month, &today.day, &today.year); whatdate=date_nextweek(today); // 函数的实参以及返回值都是结构类型 printf(The date after 7 days is %d-%d-%d!\n, whatdate.month, whatdate.day, whatdate.year); }
struct ymd date_nextweek(struct ymd d) { struct ymd newd; if(d.year%4==0&&d.year%100!=0||d.year%400==0) days[2]=29; else days[2]=28; newd.day=d.day+7; newd.month=d.month; newd.year=d.year; if (newd.day>days[d.month]) { newd.day=newd.day-days[d.month]; newd.month=newd.month+1; if (newd.month>12) { newd.month=1; newd.year=newd.year+1; } return (newd);
10.5 链表处理 10.5.1 链表结构 1.链表的概念 链表是用指针把各个结点链接在一起,其一般形式如图所示。 指向链表的首结点 10.5 链表处理 10.5.1 链表结构 1.链表的概念 链表是用指针把各个结点链接在一起,其一般形式如图所示。 指向链表的首结点 尾结点,NULL:链表结束标志 指向后续结点的指针,存放后续结点的地址 存储结点本身的数据信息
【例10.7】 建立一个简单的链表,它由3个存放学生数据(包括学号和成绩)的结点组成,然后输出各结点的数据。 #include "stdio.h" struct node /*定义结构体类型*/ { int num; /*学号*/ float score; /*成绩*/ struct node *next; /*指向struct node类型的指针变量*/ }
main( ) { struct node a,b,c,*head,*p; a.num=101; a.score=85.4; b.num=103; b.score=96.1; c.num=105; c.score=77.5; head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head; do { printf("学号: %d 成绩:%5.2f\n",p->num,p->score); p=p->next;} while(p!=NULL); } 静态链表
2.动态存储分配函数 (1)分配内存空间函数malloc() 调用形式: (类型说明符*) malloc(size); 例如: pc=(char *) malloc (sizeof(char)); 表示分配1个字节的内存空间,并强制转换为字符类型,函数的返回值为指向该字节的指针,把该指针赋予指针变量pc。
(2)分配内存空间函数 calloc() 调用形式:(类型说明符*) calloc(n,size); 说明:“(类型说明符*)”用于强制类型转换。 calloc()函数与malloc()函数的区别仅在于一次可以分配n块区域。 例如: ps=(struet stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的结构体长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。
(3)释放内存空间函数free() 调用形式:free(void *ptr); 功能:释放ptr所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc()或calloc()函数所分配的区域。
ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; 【例10.8】 分配一块区域,输入一个学生数据。 #include "stdlib.h" #include "stdio.h" main( ) { struct stu { int num; char *name; char sex; float score; } *ps; ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; ps->name="Zhang ping"; ps->sex='M'; ps->score=62.5; printf("Number=%d \nName=%s \n",ps->num,ps->name); printf("Sex=%c \nScore=%f \n",ps->sex,ps->score); free(ps); }
10.5.2 对链表的基本操作 对链表的常用的操作主要包括创建、插入、删除和输出等基本操作。 创建链表 10.5.2 对链表的基本操作 对链表的常用的操作主要包括创建、插入、删除和输出等基本操作。 创建链表 【例10.9】 编写一个create()函数,按照规定的结点结构,创建一个单链表。 基本思路: 首先向系统申请一个结点的空间,然后输入结点数据域中的数据项,并将指针域置为空(链尾标志),最后将新结点插入到链表尾。对于链表的第一个结点,还要设置头指针变量。 本题中设3个指针变量head、new1和tail,分别说明如下: head:头指针变量,指向链表的第一个结点,用作函数返回值。 new1:指向新申请的结点。 tail:指向链表的尾结点,用tail->next=new1,实现将新申请的结点,插入到链表尾,使之成为新的尾结点。
#include "stdio.h" #include "malloc.h" #define NULL 0 #define LEN sizeof(struct student) /*定义结点长度*/ struct student /*定义结点结构*/ { int num; /*学号*/ float score; /*成绩*/ struct student *next; /*指针域*/ };
struct student *create() /*create()函数: 创建单链表*/ { struct student *head=NULL, *new1, *tail; int count=0; /*链表中的结点个数(初值为0)*/ new1=tail=(struct student *)malloc(LEN); /*向系统申请一新结点空间*/ scanf("%d%f",&new1->num,&new1->score); while((new1->num)!=0) /*如果学号0,则退出*/ { count++; /*结点个数加1*/ if(count==1) head=new1; /*将新结点插入到链表尾,并设置新的尾指针*/ else tail->next=new1; /*非首结点, 将新结点插入到链表尾*/ tail=new1; /*设置新的尾结点*/ new1=(struct student *)malloc(LEN); scanf("%d%f",&new1->num,&new1->score); } tail->next=NULL; return(head); /*返回单链表的头指针*/ }
S->next =p->next; p->next= S; 3. 插入操作 在结点a与b之间插入一个新的结点x。插入前,结点a是结点b的前驱结点,结点b是结点a的后继结点;插入后,新插入的结点x成为结点a的后继结点、结点b的前驱结点。 算法如下: S->next =p->next; p->next= S; 结点插入前的链表 结点插入后的链表
【例10.10】 编写insert()函数,完成在单链表的第i个结点后插入1个新结点的操作。 struct student *insert(struct student *head, struct student *stu, int i) { struct student *pointer; if(head==NULL) /*若为空链表*/ head=stu, stu->next=NULL; /*将新结点插入到空链表中*/ else /*非空链表*/ if(i==0) stu->next=head, head=stu; /*使新结点成为链表新的首结点*/ else /*其他位置*/ { pointer=head; /*查找单链表的第i个结点(pointer指向它)*/ for(; pointer!=NULL && i>1; pointer=pointer->next, i--) if(pointer==NULL) /*越界错*/ printf("Out of the range, can't insert new node!\n"); else /*一般情况:pointer指向第i个结点 */ stu->next=pointer->next, pointer->next=stu; } return(head);
pa->next=px->next; free(px); 4. 删除操作 删除结点x。删除前,结点x是结点b的前驱结点、结点a的后继结点;删除后,结点a成为结点b的前驱结点,结点b成为结点a的后继结点。 结点删除前的链表 结点删除后的链表 pa->next=px->next; free(px);
【例10.11】 编写一个dele ()函数,删除链表中学号为num的指定结点。 struct student *dele( struct student *head, int num) { struct student *pf,*pb; if(head==NULL) /*若为空表,输出提示信息*/ { printf("\nempty list!\n"); return head; } pb=head; while (pb->num!=num && pb->next!=NULL) /*当前结果不是要删除的结点,而且也不是最后一个结点时,继续循环*/ { pf=pb; pb=pb->next; } /*pf指向当前结点,pb指向下一结点*/ if(pb->num==num) { if(pb==head) head=pb->next; /*找到被删结点,且为第一结点,则使head指向第二个结点,否则使pf所指结点的指针指向下一结点的后续*/ else pf->next=pb->next; free(pb); printf("The node is deleted\n"); } else printf("The node not been foud!\n");
5. 输出链表 首先知道head头指针的值,设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出,直到链表的尾结点。 【例10.12】 输出链表。 void output (struct student *head) { struct student *p; p=head; if(head!=NULL) do { printf("%d %5.1f\n", p->num , p->score); p=p->next; } while(p!=NULL); }
例 创建一个链表,用来存储下表所示n条的学生成绩记录表。 功能要求: (1) 学生成绩信息由键盘录入,一个记录一行; (1) 学生成绩信息由键盘录入,一个记录一行; (2)可插入记录到链表中,由用户指定插入位置; (3 )查找指定位置的记录(链表中的位置而非排序的顺序编号); (4 )可以进行记录的修改或删除; (5 )可以按照链表的组织顺序打印记录, (6 )可以对链表记录排序。 以上每个功能处理后都提供按链表顺序打印记录和排序输出记录的功能。 输入的一行记录如下,中间用制表或空格符分隔开: 0053864 智婷 女 SystemView仿真 C01 072 20.0 89.0 91.2
//定义学生记录结构类型及对应的指针类型 typedef struct studentrec 步骤1.首先应该根据记录的各个数据项目,相应的定义一个成绩记录结构体类型,用来保存数据: /*文件名:mysubs.h*/ //定义学生记录结构类型及对应的指针类型 typedef struct studentrec { char number[8]; //保存学生7位学号字符串 char name[21]; //保存学生姓名,最长10个中文字 char gender; //性别,取值为'M'或'F' char course[30]; //课程名 char classno[5]; //课程编号 char semester[4]; //开课学期 float pingshi, final, score;//平时分,期末分,总评分 struct studentrec *next; //指针,指向下一个记录 } STUREC, * PSTUREC;
步骤2.创建链表。 首先应该创建一个具有N个结点的链表,同时输入数据记录。创建链表,首先应该创建一个个的结点,并把各结点用指针连接起来。第一个结点为首元素结点,又叫表头;指向它的指针称为链表的表头指针。每个链表必须有一个表头指针。 步骤2.1.开始的时候,链表是空的,空表的表头指针值为NULL。还要创建一个表尾结点指针,开始也为NULL。 (0) 创建空表 表头指针 head = NULL 表尾指针 tail = NULL
步骤2.2.创建一个结点p,作为首元素结点,同时也是尾结点: 记录1数据 NULL head 表头指针 首元素结点 (1) 创建首元素结点 p tail /*文件名:mysubs.cpp*/ #include“mysubs.h“ /*CreateRecNode:创建链表结点。成功则返回指向 该结点的指针,否则返回NULL*/ PSTUREC CreateRecNode( ) { PSTUREC p=( PSTUREC)calloc(1, sizeof(STUREC));//用calloc创建结 点,保证内存中都是0 return p; }
PSTUREC CreateRecNode( );//创建链表结点。成功则返回指向该结 PSTUREC InputRecord(PSTUREC p);//输入学生成绩记录数据,该记录由p00 PSTUREC CreateLst(int n)00/*创建有n个结点的链表,返回表头指针*/0 { PSTUREC head, tail, p = NULL;00int i=0;00 0 tail = head = NULL; //(2.1)创建空链表00 0 while(i<n) //循环创建n个结点的链表00 {0 p=CreateRecNode();//创建一个结点 00 if(p==NULL)0 0 {0printf("创建结点失败!退出程序......\n");0 0 exit(-1);0 }00 p->next = NULL;//把新建的、由p指向的结点作为尾结点 00 if(head==NULL) //(2.2) 创建首元素结点后,把它链入链表 00 tail=head=p; 00 else //(2.3) 把新建的非首元素结点连在链表最后作为新的尾结点 00 {0 tail->next=p; //把新建结点挂在尾部0 0 tail =p; //新建结点作为新的尾结点 }0 0 InputRecord(p); //输入数据 00 i++; //创建下一个结点0 }0 0 return head; //返回链表表头指针 }
步骤3 实现函数InputRecord。 这个函数根据用户输入的一行信息,从中提取出用空白符(空格、制表符等)分隔开的各项数据,利用它们分别为形参指针p指向的struct studentrec类型的结构体的各成员变量赋值。采用一行一行的输入(利用函数fgets),是为了简化输入的麻烦,而且还能保证输入的安全。这样,用户就可以先把用空白符分隔的一行行的记录存放在一个文本文件中,在程序要求输入数据的时候,用拷贝-粘贴的方式很快捷的把记录输入程序中。 PSTUREC InputRecord( PSTUREC p ) 000 { if(p == NULL ) return; //指针p不为NULL时才允许接受输入 char line[200]={'\0'};000 char gender[3]; //用来保存性别字串"男""女"000 fflush(stdin); //输入记录前先清空输入缓冲区00 fgets(line, sizeof(line), stdin); //用fgets从控制台输入一行数据00 sscanf(line,"%s%s%s%s%s%s%f%f%f\n", p->number,p->name, gender,00 p->course, p->classno, p->semester, &(p->pingshi),00 &(p->final),&(p->score) ); //读取数据,写到结构的成员变量中00 if(strcmp("男",gender)==0) p->gender = 'M'; //把性别转换成字符值'F'/'M '00 else p->gender = 'F';00 return;00 }
步骤4.检验链表创建的结果,设计打印链表数据的函数。 步骤4.1.首先设计打印单条记录的函数。该函数根据输入的指向记录的指针,分别打印各个字段: 000 /*PrtStuRec:打印单个学生成绩记录,利用指向学生成绩结构体的指针p*/000 void PrtRecord(PSTUREC p) //打印结构体中所有成员变量的函数,采用传指针的方式000 { (p!=NULL)&& printf("%-8s%-8s%5s%20s%7s%7s%8.1f%8.1f%8.1f\n",p->number, p->name, 00 (p->gender=='F')?"女":"男",p->course, p->classno, p->semester, 0005 p->pingshi, p->final, p->score );//用指针来存取成员变量0006 return ;0007 }
步骤4.2.能够打印单条记录了,接下来设计打印整个链表表示的所有记录的函数。其实只需要从链表的表头开始,逐条打印记录,直至表尾即可。 void PrtStuRecLst(PSTUREC head) { PSTUREC p=head; int i =0; if(p==NULL ) return; printf("===============================================================================\n"); printf("学号 姓名 性别 课程名 班级 学期 平时分 期末分 总评\n"); do PrtRecord(p); }while(p=p->next); return ; }
10.6 共用体和枚举类型 10.6.1 共用体 共用体类型的定义与结构体类型的定义类似,格式为: union 共用体类型名 { 成员列表; }; 1. 间接定义──先定义类型、再定义变量。 例如:定义data共用体类型变量un1,un2,un3的语句如下: union data { int i; char ch; float f; }; union data un1,un2,un3; 2. 直接定义──定义类型的同时定义变量。 union [data] float f; } un1, un2, un3;
10.6.2 枚举类型 枚举类型的定义为: enum 枚举类型名 {取值表}; 10.6.2 枚举类型 枚举类型的定义为: enum 枚举类型名 {取值表}; 如:enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 枚举类型变量的定义与结构体变量类似。 例如:enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat } workday;
10.7 定义已有类型的别名 在C语言中,可以用typedef关键字来为系统已经有的数据类型定义别名,该别名与标准类型名一样,可以用来定义相应的变量。 例如: typedef int INTEGER; /*指定别名INTEGER代表int*/ typedef float REAL; /*指定别名REAL代表float */ INTEGER x,y;等价于int x,y; REAL a,b;等价于float a,b;
也可以声明一个新的别名DATE代表一个结构体类型。 例如: typedef struct date { int month; int day; int year; }DATE; 下面可以用DATE定义变量 DATE birthday; /*定义结构体变量*/