第9章 结构体
目 录 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 目 录 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 重点是函数的定义、引用、函数间数据传递的方式、变量的作用范围。 难点是函数的递归调用。 外部函数与外部变量的应用。 用typedef定义类型
本章学习目标 理解结构体的概念和它对于编程的重要性; 理解定义结构体类型和定义结构体变量的区别; 能够用“ . ”和“->”分量运算符操作结构体变量和指向结构体的指针变量; 能够定义并使用结构体数组; 了解用typedef定义数据类型。
有些问题仅用基本类型和数组来描述,无法反映其内在联系,如学生情况: 9.1 定义和使用结构体变量 有些问题仅用基本类型和数组来描述,无法反映其内在联系,如学生情况: num name sex age score addr 11001 Zhang xin m 19 96. 5 Shang hai 12001 Wang li f 20 98. 5 Bei jing 由不同类型数据组成的这种数据结构称为结构体(structure)。
注意:这只是声明一种数据类型并没有定义变量。 1、结构体 结构体是一种构造数据类型。 定义:由相互关联的不同数据类型的数据组成的有机整体。 用途:为处理复杂的数据结构提供了手段。 为函数间传递不同类型的参数提供了便利。 关键字:struct 结构体类型定义 注意:这只是声明一种数据类型并没有定义变量。 合法标识符 可省:无名结构体 struct [结构体名] { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; 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、定义结构体类型变量的方法(3种) (1)先声明结构体类型,再定义结构体变量 定义结构体 类型 struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2; 定义结构体变量
(2)声明结构体类型的同时定义结构体变量 struct student struct 结构体名 { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu1,stu2 ; struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }变量名表列; 定义结构体类型 只有在定义了结构体变量后系统才为其分配内存。 定义结构体变量
(3)直接定义结构体类型变量 struct struct { int num; { 类型标识符 成员名; char name[20]; char sex; int age; float score; char addr[30]; } stu1,stu2 ; struct { 类型标识符 成员名; 类型标识符 成员名; ……………. }变量名表列; 用无名结构体直接定义变量只能一次
说明 结果:28 printf ("%d ", sizeof (stu) ); 结构体类型与结构体变量概念不同 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体变量中的成员可单独使用,方法如普通变量; 结构体可嵌套 struct date { int month; int day; int year; }; struct student { int num; char name[20]; struct date birthday; }stu; struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu; num name birthday month day year printf ("%d ", sizeof (stu) ); 结果:28
struct student { int num; char name[20]; float score; }stu; int num; 结构体成员名与程序中变量名可相同,两者不代表同一个对象。 struct student { int num; char name[20]; float score; }stu; int num; stu. num num
3、 结构体变量的引用 结构体变量名.成员名 结构体变量不能整体引用,只能引用变量成员 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1.num=10; stu1.age++; stu1.score=85.5; stu1.score+=stu2.score; 成员(分量)运算符 优先级: 1 结合性:从左向右
main() { struct student { int No; float score; } stu1,stu2; } scanf(“%d,%f”,&stu1); () scanf(“%d,%f”,&stu1.No, &stu1.score); (√) printf(“%d,%f”,stu1); () printf(“%d,%f” , stu1.No, stu1.score); (√) stu2=stu1; (√)
结构体变量的成员与普通变量用法相同。 结构体成员本身又是一个结构体类型,则需要找到最低一级的成员。 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; 结构体变量的成员与普通变量用法相同。
4、 结构体变量的初始化 形式一 struct 结构体名 { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; struct 结构体名 结构体变量={初始数据}; struct stu { int num; char name[20]; int age; char addr[30]; }; struct stu a={112,“Wang Lin”, 19, “200 Beijing Road”};
形式二 struct 结构体名 { 类型标识符 成员名1; 类型标识符 成员名2; ……………. } 结构体变量={初始数据}; { 类型标识符 成员名1; 类型标识符 成员名2; ……………. } 结构体变量={初始数据}; struct stu { int num; char name[20]; int age; char addr[30]; } a={112,“Wang Lin”, 19, “200 Beijing Road”};
形式三 struct { 类型标识符 成员名; 类型标识符 成员名; ……………. }结构体变量={初始数据}; struct { 类型标识符 成员名; 类型标识符 成员名; ……………. }结构体变量={初始数据}; struct { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
#include <stdio.h> void main() { struct student { long int num; 例9.1 对结构体变量初始化 #include <stdio.h> void main() { struct student { long int num; char name[20]; char sex; char addr[20]; }a={89031,“Li Lin”,‘M’, “123 Beijing Road”}; printf("No. :%ld\nname:%s\nsex:%c\naddress:%s\n", a.num,a.name,a.sex,a.addr); }
9.2 结构体数组 具有相同结构的结构体也可以组成数组 定义结构体数组:3种形式 形式一:间接定义 struct student 9.2 结构体数组 具有相同结构的结构体也可以组成数组 定义结构体数组:3种形式 num name sex age stu[0] stu[1] 25B 形式一:间接定义 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];
结构体数组初始化 struct 结构名 结构数组名[数组长度]={初始数据}; 定义数组时初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[3]={{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[3]={{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}, ……}; stu[0].age++; strcpy(stu[0].name, “ ZhaoDa”);
“.”成员运算符优先于“++”,所以Leader[j].count++相当于(learer[j].count)++ 例9.3 统计候选人选票 #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]; 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);} name count Li Zhang Wang 4 3 name count Li Zhang Wang 全局结构体数组 “.”成员运算符优先于“++”,所以Leader[j].count++相当于(learer[j].count)++
9.3 指向结构体类型数据的指针 指向结构体变量的指针 例 struct student *p; struct student 9.3 指向结构体类型数据的指针 存放结构体首地址 指向结构体变量的指针 定义形式: struct 结构体名 *结构体指针名 例 struct student *p; 存放结构体变量在内存的起始地址 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 以下三种形式等价: 结构体变量名.成员名 stu.num =101; (*结构体指针名).成员名 (*p).num=101 结构体指针名成员名 pnum =101 指向运算符 优先级: 1 结合方向:从左向右 ( )不能少!
例9.5 指向结构体变量的指针的应用 #include <stdio.h> #include <string.h> void 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'; pscore=89.5; printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n", (*p).num,pname,stu_1.sex,pscore);}
指向结构体数组的指针 数组首地址赋给指向结构体类 型的指针变量 当指针变量增1时,指向下一个 数组元素。 p num name stu[0] sex age stu[0] p stu[1] stu[2] p+1
例9.6 指向结构体数组的指针的应用 #include <stdio.h> struct student { int num; 例9.6 指向结构体数组的指针的应用 #include <stdio.h> 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}}; void main() { struct student *p; for(p=stu;p<stu+3;p++) printf("%d%s%c%d\n",pnum,pname,psex,page);} num name sex age stu[0] p stu[1] stu[2] p+1 p=str[1].name (×) p=(struct student *)stu[1].name (√) 强制转换
运行结果: 11 200 20 300 注意区分以下三种运算( > 优先级比++高) ①p >n ② p >n++ ③ ++p >n struct s { int x; int y; }data[4]={10,100,20,200,30,300,40,400}; void main( ) { struct s *pointer=data; printf("%d\n",++pointerx); printf(("%d\n",(++pointer)y); printf("%d\n", (pointer++)x); printf("%d\n", (pointer)y++); } 取x值加1后输出 运行结果: 11 200 20 300 地址加1后再取y值 先取当前地址x值 再地址加1 y值输出后地址 再加1
用结构体变量和指向结构体的指针作函数参数 将一个结构体变量的值传递给另一函数 , 方法有3种: 用结构体变量的成员作函数实参----值传递 注意形、实的类型要一致。 用指向结构体变量或数组的指针作实参----地址传递 传递的是结构体变量的地 址。 用结构体变量作参数----多值传递,效率低 将结构体变量所占的内存单元的内容全部顺序传递给形参,要求形参与实参同类型。函数调用是单值传递,且形参占用内存单元,若形参的值被改变,不会返回主调函数。
例9.7 结构体变量stu有学号、姓名和3门课成绩, 在main函数中赋值,在print函数中打印输出。 #include <stdio.h> #include <string.h> #define FORMAT "%d\n%s\n%f\n%f\n%f\n" struct student /*定义为外部结构体类型*/ { int num; char name[20]; float score[3];}; void main() { void print(struct student); struct student stu; /*定义为局部结构体类型变量*/ stu.num=12345; strcpy(stu.name,"Li Li"); stu.score[0]=67.5;stu.score[1]=89;stu.score[2]=78.6; print(stu); /*结构体变量作实参*/ } void print(struct student stu) { printf(FORMAT,stu.num,stu.name,stu.score[0],stu.score[1],stu.score[2]); printf(“\n”);} 无"&" /* 对成员赋值也可以改为scanf函数输入*/ scanf("%d%s%f%f%f",&stu.num,stu.name, &stu.score[0],&stu.score[1],&stu.score[2]);
将例9.7改为用结构体变量的指针作实参 #include <stdio.h> #define FORMAT "%d\n%s\n%f\n%f\n%f\n" struct student /*定义为外部结构体类型*/ { int num; char name[20]; float score[3]; }; stu={12345, "Li Li",67.5,89,78.6}; void main() { void print(struct student * ); /*形参指向结构体的指针变量*/ print(&stu); /*实参为stu的起始地址*/ } void print(struct student *p) { printf(FORMAT,pnum,pname,pscore[0],pscore[1], pscore[2]); /*用指针变量调用成员之值*/ printf(“\n”);
9.4 用指针处理链表 数组:静态分配存储单元,容易造成内存浪费。 链表:是重要的数据结构,它根据需要,动态分配内存单元 。 head 9.4 用指针处理链表 数组:静态分配存储单元,容易造成内存浪费。 链表:是重要的数据结构,它根据需要,动态分配内存单元 。 head 1249 1356 1475 1021 A B C D Null 特征:头指针变量,存放链表首地址,链表中每个元素称结点,其内容: 数据部分:可有若干项(整、实、字符、结构体类型等) 指针变量:下一结点的地址,最后一个结点(表尾)的地址部分为NULL。
它指向struct student数据类型. struct student { int num; float score; 链表各结点的特点: 在内存中可以不连续,访问某结点应找上一结点提供的地址,每一结点有一指针变量存放下一结点的地址。 链表的每个结点实际上是一个结构体变量,它有若干成员组成 其中:next是成员名,是指针类型, 它指向struct student数据类型. struct student { int num; float score; struct student *next; }; 99101 89. 5 99103 90 99107 85 NULL num score next
简单链表 例9.8 建立简单链表,它由3个学生数据的结点组成。 输出各结点中的数据。 #include <stdio.h> 例9.8 建立简单链表,它由3个学生数据的结点组成。 输出各结点中的数据。 #include <stdio.h> #define NULL 0 struct student {long num; float score; struct student *next; }; void main( ) {struct student a,b,c,*head,*p; a.num=99101;a.score=89.5; b.num=99102;b.score=90; c.num=99103;c.score=85; head=&a;a.next=&b;b.next=&c; c.next=NULL; p=head; do { printf(“%ld %5.1f\n”,pnum,pscore); p=pnext; }while(p!=NULL); }
每个结点都属于struct student类型,它的next成员存放下一个结点的地址,这样一环扣一环,将各结节紧密的扣在一起,最后一次循环,将p=pnext是将c结点的地址赋给p,这时p指向c结点,然后将c结点的num,score输出,之后将p=pnext实际上是将c结点的next内容,即NULL赋给p 再进行判断, P!=NULL条件不成立,循环结束。 本例所有结点是在程序中定义的,不是临时开辟的,用完也不能释放,这种链表称“静态链表”。
处理动态链表所需的函数 为处理动态链表,C提供了开辟和释放存储单元的函数: malloc函数 calloc函数 函数原型:void *malloc(unsigned int size); 作用:在动态区分配一个长度为size的连续空间,函数返回值是一个指向分配域起始地址的指针,如内存空间不足,返回空指针NULL。 (此处:void为无确定类型) calloc函数 函数原型:void *calloc(unsigned n,unsigned size); 作用:在内存动态区分配n个长度为size的连续空间,函数返回指向分配域起始地址的指针,若分 配不成功,返回NULL值。
注:旧版本提供的malloc和calloc函数得到的是指向字符型数据的指针。 free函数 函数原型:void free(void *p); 作用:释放由p指向的内存区,使这部分内存区能被其它变量使用。P所指向的是最近一次calloc或malloc分配的存储区域。 free函数无返回值。 注:旧版本提供的malloc和calloc函数得到的是指向字符型数据的指针。 ANSI C提供的malloc和calloc函数规定为void *类型,这并不是说该函数调用后无返回值,而是返回一个结点的地址,该地址的类型为void(无类型或类型不确定),即一段存储区的首址,其具体类型无法确定,只有使用时根据各个域值数据再确定。
建立动态链表 建立动态链表:是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。 例9.9 写一函数建立一个有3名学生数据的单向动态链表。 思路: ⑴ 设置3个指针变量head、p1、p2 head:指向链表头的指针变量,初始化head=NULL。 p1:指向后继结点的首地址的指针变量 p2:指向结点成员next的指针变量。 next的值是下一个结点的首地址。 ⑵ 循环方式用malloc函数开辟第1个结点。n=1 p1、p2指向第1结点首地址(见下页插图) 输入数据,如果p1num !=0, 则head=p1结点链入链表,反之不链入。
(n=1) 99101 89.5 head p1 p2 (a) (n=2) head p2 p1 99101 89.5 99103 90 输入数据。 如果p1num !=0,链入2结点, 方法: p2next=p1 (a) (n=2) head p2 p1 99101 89.5 99103 90 ⑷ 为建立第3个结点做准备: p2=p1,腾出p1 。 head p2 p1 99101 89.5 99103 90 (c) (n=2) head p2 p1 99101 89.5 99103 90 (b) (n=2)
⑸ 重复⑶⑷两步开辟第3个结点,并链入链表。 99101 89.5 99103 90 head p2 p1 99107 85 (a) n=3 n=n+1 n==1 head=p1 p2next=p1 真 假 (把p1所指结点作为第一个结点) (把p1所指结点连接到表尾) p2=p1 (p2移到表尾) 再开辟一个新结点,使p1指向它 读入一个学生数据给p1所指结点 表尾结点的指针变量置NULL 开辟一个新结点,并使p1, p2指向它 读入一个学生数据给p1所指向的结点 head=NULL, n=0 当读入的p1 num 不是零 99101 89.5 99103 90 head p2 p1 99107 85 (b) n=3
⑹ 再开辟新结点,由于num数据为0,退出循环。 并使p2next=NULL,虽然p1指向新结点但没有链入链表。 99101 89.5 99103 90 p2 p1 99107 85 (a) n=3 head 99101 89.5 99103 90 p2 p1 99107 85 NULL (b) n=3 head
#include “stdio.h” #include “malloc.h” #define NULL 0 #define LEN sizeof (struct student) struct student {long num; float score; struct student *next; }; int n; struct student *creat(void) { struct student *head; struct student *p1, *p2; n=0; p1=p2=(struct student *) malloc(LEN); scanf(“%ld,%f”,&p1 num, &p1 score); head=NULL; while(p1 num !=0) {n=n+1; if(n==1)head=p1; else p2 next=p1; p2=p1; p1=(struct student *)malloc (LEN); scanf(“%ld,%f”,&p1 num, & p1 score); } p2 next=NULL; return(head); }
#include “stdio.h” /*改进后*/ #include “stdlib.h” #define NULL 0 #define LEN sizeof (struct student) struct student {long num; float score; struct student *next; }; int n; struct student *creat(void) { struct student *head; struct student *p1, *p2; flot s; n=0; p1=p2=(struct student *) malloc(LEN); scanf(“%ld,%f”,&p1 num,&s); p1 score=s; head=NULL; while(p1 num !=0) {n=n+1; if(n==1)head=p1; else p2 next=p1; p2=p1; p1=(struct student *)malloc (LEN); scanf(“%ld ,%f”,&p1 num,&s); p1 score=s; } p2 next=NULL; return(head); }
设一个指针变量p,找到链表第1个结点的地址(head的值),p指向该结点,输出结点各成员的数据,再p后移指向下一结点。 输出链表 思路: 设一个指针变量p,找到链表第1个结点的地址(head的值),p指向该结点,输出结点各成员的数据,再p后移指向下一结点。 P=head,使p指向第一个结点 P指向的不是尾结点 真 假 输出p所指向的结点 p=p next 当p指的不是表尾 NULL head P P’
void print( struct student *head) { struct student *p; printf(“\n Now, these %d records are :\n”, n); p=head; if(head) !=NULL) do { printf(“%ld, %5.2f\n”, p num, p score); p=p next; } while(p !=NULL);
对链表的删除操作 并不真从内存中抹掉,只是把它分离,再前后结点相链接。 例9.11 写一函数删除动态链表中指定的结点。 例9.11 写一函数删除动态链表中指定的结点。 思路:本例以学号作为删除结点的标志(查找对象)。 ⑴ 设两个指针变量p1和p2。从head开始,p1依次指向各结点查找num值是否等于要删除结点的学号。每次下移前使p2=p1。学号相等删除该结点,直至查到表尾。 p2 (b) 下移一个结点 head p1 99107 NULL 99101 99103 p2=p1 99101 head p1 99103 99107 NULL (a) 初始状态
⑵找到要删除的结点后: ①如果要删除的是第1结点,则head=p1next 。head指向第二结点,第一结点脱离。 head p2 p1 p2 next=p1 next (d) 第二个结点被删除 99107 NULL 99101 99103 head=p1 next head p1 (c) 选中第一个结点 99101 99107 NULL 99103 ②如果要删除的不是第1结点,则p2next=p1next 。P1指向的结点脱离。 ③还要考虑链表为空和链表中没有要删除的结点的情况。
p1是要删除的结点 是 否 链表是一个空表 真 假 输出 空表 p1=head 当num≠ p1 num 以及p1 所指的结点不是表尾结点 p2=p1 (p2后移一个位置) p1 = p1 next (p1后移一个位置) 输出“找不 到”的信息 P1所指是头结点 是 否 head=p1 next (删除头结点) p2next=p1next (删除一个结点)
struct student *del(struct student *head,long num) { struct student *p1,*p2; if(head = = NULL) {printf(“\n list null ! \n”); goto end; } p1=head; while(num !=p1 num && p1 next != NULL) { p2=p1; p1=p1 next; } if(num == p1 num) { if(p1 = = head) head=p1 next; else p2 next = p1 next; printf(“delete: %d\n”,num); n=n-1; } else printf(“%ld not been found ! \n”,num); return(head);
对链表的插入操作 假设结点按成员的学号从小到大排列,按排序顺序插入结点。 思路:找到插入点后,将该点的next值指向新结点,并使新结点的next值等于断点后面结点的首地址。 ⑴ 设置p0、p1、p2三个指针变量。创建一个新结点,p0指向其起始位置地址。p1指向第1个结点。 head 99101 99103 99107 NULL 99102 p0 p1 (a)准备将p0插入链表中
⑵ 如果p0num大于p1num,则p2=p1,然后p1后移一个结点。直至p0num小于或等于p1num。这时p0所指结点插在p1所指结点之前。 head 99101 99103 99107 NULL 99102 p0 p1 p2 (b) 插入点位于链表中间 p0num>p1num p2=p1, p1=p1next 99103 99107 NULL p1 head 99101 99102 p0 p2 (c) 链接新结点 p0num ≤p1num p2next=p0, p0next=p1 ⑶ 如果插入点在链表中间,则p2next=p0,p0next=p1,新结点插入了链表。
⑷ 如果插入点位于最前面,则head=p0,p0 next=p1。 99107 NULL head 99100 99103 99101 p0 p1 (d) 结点插在表首 p0num < p1num head=p0, p0next=p1 p1 99101 99107 99103 99109 NULL p0 (e) 结点插在表尾 p1next = p0 p0next = NULL head ⑸ 如果插入点位于最后面,则p1不再后移,p1next=p0, p0next=NULL
将一个结点插入到链表中算法: p1=head, p0=stud 原来的链表是空表 是 否 是 否 当p0 num > p1 num 以及p1所指的不是表尾结点 p2=p1 p1=p1 next p0 num ≤p1 num 真 假 P0指向头结点 是 否 head=p0 p0 next=p1 (插到表头之前) p2 next=p0 (插到表中间) p1 next=p0 p0 next=NULL (插到表尾之后) 将p0所 指的结 点作为 唯一结 点 n=n+1
{ struct student *p0, *p1, *p2; p1=head; /*使p1指向第一个结点*/ struct student *insert(struct student *head, struct student *stud) { struct student *p0, *p1, *p2; p1=head; /*使p1指向第一个结点*/ p0=stud; /*p0指向要插入的结点*/ if(head = = NULL) /*原来的链表是空表*/ {head=p0; p0next=NULL; } /*使p0指向的结点作为头结点*/ else { while((p0num > p1num) && (p1next != NULL)) { p2=p1; /*使p2指向刚才p1指向的结点*/ p1=p1 next; } /*p1后移一个结点*/ if(p0num <= p1num) { if(head == p1) head=p0; /*插到原来第一个结点之前 */ else p2next=p0; /*插到p2指向的结点之后*/ p0next = p1; } else {p1next=p0; p0next=NULL; } /*插到最后的结点之后*/ } n=n+1; /*结点数加1*/ return(head);
对链表的综合操作 用main函数作主调函数,调用前述建立、输出、删除、插入结点的函数。 void main( ) { struct student *head, *stu; long del_num; printf(“input records: \n”); head=creat(); /*建立链表,返回头指针*/ print(head); /*输出全部结点*/ printf(“\n input delete number:”); scanf(“%ld”, &del_num); /*输入要删除的学号*/ while(del_num !=0) { head=del(head,del_num); /*删除后链表的头地址*/ print(head); /*输出全部结点*/ printf(“input the delete number:”); scanf(“%ld”, &del_num); /*输入要删除的学号*/ }
printf(“\n input the inserted record:”); stu=(struct student *) malloc(LEN); /*输入要插入的结点*/ scanf(“%ld,%f”, &stunum, &stuscore); while(stunum !=0) { head=insert(head,stu); /*插入新结点,返回地址*/ print(head); /*输出全部结点*/ printf(“input the inserted record:”); }
9.7 用typedef定义类型 功能:用自定义名字为已有数据类型命名 类型定义简单形式: typedef type name; 例 typedef int INTEGER; 例 INTEGER a,b,c; REAL f1,f2; 类型定义语句关键字 已有数据类型名 用户定义的类型名 例 typedef float REAL; int a,b,c; float f1,f2; 说明: 1.typedef 没有创造新数据类型 2.typedef 是定义类型,不能定义变量 3.typedef 与 define 不同 类型定义后,与已有类型一样使用 define typedef 预编译时处理 编译时处理 简单字符置换 为已有类型命名
typedef定义类型步骤 类型定义可嵌套 ① 按定义变量方法写出定义体 如 int i; ② 将变量名换成新类型名 如 int INTEGER; ③ 最前面加typedef 如 typedef int INTEGER; ④ 用新类型名定义变量 如 INTEGER i,j; 类型定义可嵌套 例 typedef struct club { char name[20]; int size; int year; }GROUP; typedef GROUP *PG; PG pclub; 例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c; int a[100],b[100],c[100]; 例 定义结构体类型 struct date { int month; int day; int year; }DATE; 例 定义结构体类型 struct date { int month; int day; int year; }d; 例 定义函数指针类型 int (*p)(); int (*POWER)(); typedef int (*POWER)(); POWER p1,p2; int (*p1)(),(*p2)(); 例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10]; char *p; char *s[10]; 例 定义结构体类型 DATE birthday, *p; struct date { int month; int day; int year; }birthday, *p; 例 定义结构体类型 typedef struct date { int month; int day; int year; }DATE; GROUP为结构体类型 PG为指向GROUP的指针类型 GROUP *pclub; struct club *pclub;
本章小结 构造数据类型分为三种,即:结构体、共用体、枚举。这三种数据类型仍然是以变量的形式使用的,只是在定义变量的时候要确定具体的构造模式。有了这三种数据类型,就能很容易地描述和构成不同的数据结构,并对这些数据结构进行操作。