版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、v 结构体类型和结构体变量结构体类型和结构体变量v 结构体数组结构体数组v 结构体指针结构体指针 v 用指针处理链表用指针处理链表v 共用体共用体 v 枚举类型枚举类型 v 用用typedeftypedef定义类型定义类型第11章 结构体与共用体问题一:学籍管理 问题:学籍管理需要每个学生的下列数据:学号、问题:学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用姓名、性别、年龄、分数,请用C语言程序存储语言程序存储并处理一组学生的学籍。并处理一组学生的学籍。 单个学生学籍的数据结构单个学生学籍的数据结构 学号(学号(num):):int型型 姓名(姓名(name):):char
2、 型型 性别(性别(sex):):char型型 年龄(年龄(age):):int型型 分数(分数(score):):float型型单个学生学单个学生学籍的数据结籍的数据结构如何定义?构如何定义?多个学生学籍多个学生学籍的数据结构如的数据结构如何定义?何定义?l 这些信息数据之间相互关联,适合看作一个整体。这些信息数据之间相互关联,适合看作一个整体。l 但数据类型不一致,仅用已学但数据类型不一致,仅用已学数据类型无法解决数据类型无法解决。 需要构造一种新的数据类型需要构造一种新的数据类型结构体。结构体。11.1-11.4 11.1-11.4 结构体类型和结构体变量结构体类型和结构体变量是用户根据
3、自己的需要一种构造类型数据是用户根据自己的需要一种构造类型数据 。 结构体结构体由若干不同类型的数据项组成,由若干不同类型的数据项组成, 构成结构体的各个数据项称为构成结构体的各个数据项称为结构体成员结构体成员。 struct 结构体名结构体名 数据类型数据类型1 成员名成员名1; 数据类型数据类型2 成员名成员名2; 数据类型数据类型n 成员名成员名n; ; 中是组成该结构体的中是组成该结构体的成员成员。成员类型可以是成员类型可以是基本型或构造型基本型或构造型struct是是关键字关键字,不能省略不能省略l用户定义的用户定义的合法标识符合法标识符。可省可省:无名结构体无名结构体l末尾分号不能
4、省末尾分号不能省u 结构体类型声明结构体类型声明-构造自己所需的结构体类型构造自己所需的结构体类型1、结构体类型声明结构体类型声明namenumsexagescoreaddr2字节字节2字节字节20字节字节1字节字节4字节字节30字节字节.struct student int num; char name20; char sex; int age; float score; char addr30; ; 结构体名成员名例例 声明结构体类型声明结构体类型struct student注意:结构体类型声明只是定义了一种新注意:结构体类型声明只是定义了一种新的类型,类似的类型,类似int等类型。它是对
5、结构的组等类型。它是对结构的组织形式的描述织形式的描述, (类似于房屋户型图),系(类似于房屋户型图),系统还没分配实际内存空间。统还没分配实际内存空间。结构的组织形式描述结构的组织形式描述只有定义结构体类只有定义结构体类型的变量,系统才型的变量,系统才分配内存空间分配内存空间一般形式一般形式:struct 结构体名结构体名 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .;struct 结构体名结构体名 变量名表列;变量名表列;(1)(1)先定义(声明)结构体类型再定义变量名先定义(声明)结构体类型再定义变量名例例 struct student int nu
6、m; char name20; char sex; int age; float score; char addr30; ; /结构体类型的声明结构体类型的声明 struct student student1, student 2; /结构体变量的定义结构体变量的定义 2、结构体变量定义结构体变量定义有了类型后,就可以定义变量。三种形式:有了类型后,就可以定义变量。三种形式:(2)2)定义结构体类型的同时定义结构体变量定义结构体类型的同时定义结构体变量一般形式:一般形式:struct 结构体名结构体名 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .变量名表列
7、;变量名表列;例例 struct student int num; char name20; char sex; int age; float score; char addr30; student1, student 2; (3)(3)直接定义结构体变量直接定义结构体变量( (即不出现结构体名即不出现结构体名) )一般形式:一般形式:struct 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .变量名表列;变量名表列;例例 struct int num; char name20; char sex; int age; float score; char ad
8、dr30; student1, student 2; 用用无名结构体直接定义变无名结构体直接定义变量只能一次量只能一次3、结构体变量需要的内存、结构体变量需要的内存 等于结构体变量所有成员占内存之和等于结构体变量所有成员占内存之和 2 20 1 2 4 30 Num name sex age score addrstudent1student1在内存中占在内存中占59个字节,(个字节,(2+20+1+2+4+30=59)。)。利用表达式利用表达式sizeof(student1)或或sizeof(struct student)或可自动求或可自动求得得 结构体类型与结构体变量概念不同结构体类型与结
9、构体变量概念不同 类型类型:不分配内存;不分配内存; 变量变量:分配内存分配内存 类型类型:不能赋值、存取、运算不能赋值、存取、运算; 变量变量:可以可以4、结构体变量初始化结构体变量初始化 就是为成员赋初值。根据前面结构体变量定义形式的三种情况,就是为成员赋初值。根据前面结构体变量定义形式的三种情况,初始化的形式也有三种。初始化的形式也有三种。struct 结构体名结构体名 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .;struct 结构体名结构体名 结构体变量结构体变量=初始数据初始数据;例例 struct student int num; char
10、name20; char sex; int age; char addr30; ; struct student student1=100102,“WangLin”, M,20, “Beijing ”;形式一:Student1(初始化后)100102 WangLi M 20 98 Beijing 2 20 1 2 4 30 Num name sex age score addrStudent1(初始化前)此时,才真正货真价实。此时,才真正货真价实。定义类型不分配空间。定义类型不分配空间。定义变量时分配空间,但值不确定,定义变量时分配空间,但值不确定,初始化后值确定。初始化后值确定。n形式二:形
11、式二:struct 结构体名结构体名 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .结构体变量结构体变量=初始数据初始数据;例例 struct student int num; char name20; char sex; int age; char addr30; stu1=112,“Wang Lin”,M,19, “200 Beijing Road”; 5、结构体变量初始化结构体变量初始化n形式三:形式三:例例 struct int num; char name20; char sex; int age; char addr30; stu1=112,“W
12、ang Lin”,M,19, “200 Beijing Road”; struct 类型标识符类型标识符 成员名;成员名; 类型标识符类型标识符 成员名;成员名; .结构体变量结构体变量=初始数据初始数据;5、结构体变量初始化结构体变量初始化6、结构体变量使用结构体变量使用(1 1)引用规则:)引用规则:一般情况下结构体变量不能整体引用一般情况下结构体变量不能整体引用, ,只能引用变量成员只能引用变量成员引用方式:引用方式: 结构体变量名结构体变量名. .成员名成员名例例 struct student int num; char name20; char sex; int age; float
13、 score; char addr30; stu1,stu2; stu1.num=10;stu1.score=85.5;stu1.score+=stu2.score; stu1.age+;. . 成员成员(分量分量)运算符运算符优先级优先级: 1最高级最高级结合性结合性:从左向右从左向右结构体中的成员(即结构体中的成员(即“域域”),可以单独使用,它的作用与),可以单独使用,它的作用与地位相当于普通变量。地位相当于普通变量。成员名可以与程序中的变量名相同成员名可以与程序中的变量名相同,二者不代表同一对象。二者不代表同一对象。例:不能将一个结构体变量作为一个整体进行输入和输出。例:不能将一个结构
14、体变量作为一个整体进行输入和输出。只能对各个成员变量分别输入输出。只能对各个成员变量分别输入输出。 struct student int num; char name20; char sex; int age; char addr30; stu1=112,“Wang Lin”,M,19, “200 Beijing Road”; printf(“%d,%s,%c,%d,%f,%sn”,stu1); ( )printf(“%d,%s,%c,%d,%f,%sn”,stu1.num, stu1. name, stu1. sex, stu1. age, stu1. addr ); ()scanf(%d,
15、s,c,d,f,s,student1);); ( )scanf(%d,&student1.num); ()(2 2)例外:)例外: 允许将一个结构体变量直接赋值给另一个具有相同结构的允许将一个结构体变量直接赋值给另一个具有相同结构的结构体变量结构体变量例如:例如:struct student char num15; char name20; int score4; int s; student1=2007101010, wang,89,90,87,80,0; main() struct student student2; student2=student1; . 例例 struct d
16、ate int month; int day; int year; ; struct student int num; char name20; struct date birthday;student1;numnamebirthdaymonthdayyear结构体成员本身又是一个结构体类型。结构体成员本身又是一个结构体类型。例:声明例:声明struct student类型时,将成员类型时,将成员birthday指定为指定为struct date类型类型7 7、结构体类型的、结构体类型的嵌套嵌套结构体嵌套时结构体嵌套时逐级引用逐级引用(只能对最低级的成员进行赋值或存取以(只能对最低级的成员进行
17、赋值或存取以及运算)及运算)student1.birthday.month=3 ()student1.birthday=3( )11.511.5、结构体数组、结构体数组1、定义结构体数组:、定义结构体数组:每个数组元素都是一个结构体类型的数据,它们都分别包每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项。也有三种方法:括各个成员项。也有三种方法:1、定义结构体后定义、定义结构体后定义struct student int num; char name20; char sex; int age; float score; char addr30;struct student stu3
18、;2、定义结构体时同时定义、定义结构体时同时定义struct student int num; char name20; char sex; int age; float score; char addr30;stu3;struct student int num; char name20; char sex; int age; float score;stu3= 10101,李宁,M,18,87.5, 10102,张凡,M,19,99, 10103,王敏,F,20,78.5 ;定义后初始化定义后初始化struct student int num; char name20; char sex;
19、 int age; float score;;struct student stu3= 10101,李宁李宁,M,18,87.5, 10102,张凡张凡,M,19,99, 10103,王敏王敏,F,20,78.5 ; 每个数组元素的初每个数组元素的初始数据都用花括号括起始数据都用花括号括起来。来。 2 2、结构体数组的初始化、结构体数组的初始化 结构数组结构数组n初值表初值表1,初值表初值表2,.,初值表初值表n;图11-4图11-5结构体数组元素类似于一个结构体变量结构体数组元素类似于一个结构体变量 只能对结构体数组元素的成员进行输入、输出或其它基本操作只能对结构体数组元素的成员进行输入、输
20、出或其它基本操作例如:例如: struct s_type char num15; char name20; int score4; int s; stu3=2007101010, wang,89,90,87,80,0, 2007101011, Li,88,95,77,70,0, 2007101012, Jiang,79,65,69,76,0 ;main() int i; for(i=0;i3;i+) for(j=0;j4;j+) stui.s+=stui.scorej; . 3 3、结构体数组元素的使用结构体数组元素的使用例例 11.2统计侯选人选票。有三个候选人,每次输入一个统计侯选人选票。
21、有三个候选人,每次输入一个得票的候选人名,要求最后输出个人得票结果。得票的候选人名,要求最后输出个人得票结果。struct person char name20; int count; leader3=“Li”,0,“Zhang”,0,”Wang“,0; /全局结构体数组全局结构体数组main() int i,j; char leader_name20; for(i=1;i=10;i+) scanf(%s,leader_name); for(j=0;j3;j+)if(strcmp(leader_name,)=0)/看是谁得票看是谁得票 leaderj.count+; f
22、or(i=0;i-优先级优先级: 1: 1级,最高级,最高结合方向:从左向右结合方向:从左向右(* *) 与与 - - 等价等价定义形式:定义形式: struct struct 结构体名结构体名 * *结构体指针名结构体指针名; ; 例:例: struct student struct student * *p p; ;使用形式:使用形式: 使用结构体指针变量引用成员形式使用结构体指针变量引用成员形式 (*结构体指针名结构体指针名). 成员名成员名 结构体指针名结构体指针名-成员名成员名 结构体变量名结构体变量名.成员名成员名(*结构体指针名结构体指针名).成员名成员名结构体指针名结构体指针名
23、-成员名成员名结构体变量名结构体变量名.成员名成员名示例11.3main() struct student long int num; char name20; char sex; float score; stu,*p; /定义结构体变量定义结构体变量stu和结构体指针变量和结构体指针变量p p=&stu; /p指向结构体指向结构体stu stu.num=89101;/对第对第1个成员赋值个成员赋值 strcpy(,“Li Lin”);/对第对第2个成员赋值个成员赋值 p-sex=M;/利用指针对第利用指针对第3个成员赋值个成员赋值 p-score=89.5; pri
24、ntf(nNo:%ldnname:%snsex:%cnscore:%fn, (*p).num,p-name,stu.sex,p-score);运行结果:No:89101 name:LiLin sex:Mscore:89.5000002 指向结构体数组的指针指向结构体数组的指针struct student int num; char name20; char sex; int age;stu3=10101,Li Lin,M,18, 10102,Zhang Fun,M,19, 10104,Wang Min,F,20;main() struct student *p; for(p=stu;pnum,
25、p-name,p-sex,p-age);numnamesexagestu0pstu1stu2p+1指针变量也可以用来指向结构体数组中的元素。指针变量也可以用来指向结构体数组中的元素。注意:注意:p+指针移动指针移动1次,跨过一个次,跨过一个struct student结构体类型大小结构体类型大小程序分析:程序分析: 是指向是指向struct studentstruct student结构体类型数据的指针变量。结构体类型数据的指针变量。在在forfor语句中先使的初值为语句中先使的初值为stustu,也就是数组,也就是数组stustu第一个第一个元素的起始地址。在第一次循环中输出元素的起始地址。
26、在第一次循环中输出stu0stu0的各个成员的各个成员值。然后执行,使自加。加意味着值。然后执行,使自加。加意味着p p所增所增加的值为结构体数组加的值为结构体数组stustu的一个元素所占的字节数。执行的一个元素所占的字节数。执行+后后p p的值等于的值等于stu stu 1 1,指向,指向stu1stu1。在第二次循环。在第二次循环中输出中输出stu1stu1的各成员值。在执行后的各成员值。在执行后,p,p的值等于的值等于stu+2stu+2,再输出,再输出stu 2stu 2的各成员值。在执行的各成员值。在执行+后,的后,的值变为值变为stu +stu +, 已不再小于已不再小于stu+
27、3stu+3了,不再执行循环。了,不再执行循环。 图11-8请分析以下几种运算:请分析以下几种运算: -umum得到指向的结构体变量中的成员得到指向的结构体变量中的成员umum的值。的值。 -umum 得到指向的结构体变量中的成员得到指向的结构体变量中的成员umum的值,的值, 用完该值后使它加。用完该值后使它加。 -umum得到指向的结构体变量中的成员得到指向的结构体变量中的成员numnum的值加,的值加,然后再使用它。然后再使用它。 (+p)(+p)-num-num先使自加,然后得到它指向的元素中的先使自加,然后得到它指向的元素中的numnum成成员值(即员值(即1010210102)。)
28、。 (p+)-num(p+)-num先得到先得到-num-num的值(即的值(即1010110101),然后使自加),然后使自加,指向,指向stu1stu1。成员运算符成员运算符 . .指向运算符指向运算符 -优先级优先级: : 最高最高结合方向:从左向右结合方向:从左向右(* *) 与与 - - 等价等价总结:结构体成员变量引用方式总结:结构体成员变量引用方式结构体变量结构体变量.成员名成员名(*p).成员名成员名p-成员名成员名其中,其中,-称为指向运算符称为指向运算符3 用结构体变量和指向结构体的指针作函数参数用结构体变量和指向结构体的指针作函数参数 将一个结构体变量的值传递给另一个函数
29、,有将一个结构体变量的值传递给另一个函数,有3 3个方个方法法: :(1)(1)用结构体变量的成员作参数。用结构体变量的成员作参数。(2) (2) 用结构体变量作实参。用结构体变量作实参。(3) (3) 用指向结构体变量(或数组)的指针作实参,用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。将结构体变量(或数组)的地址传给形参。值传递值传递值传递,不推荐使用值传递,不推荐使用地址传递地址传递例例11.5 11.5 结构体变量作为函数参数结构体变量作为函数参数 有一个结构体变量有一个结构体变量stustu,内含学生学号、姓名和,内含学生学号、姓名和3 3门课程的门课
30、程的成绩。要求在成绩。要求在mainmain函数中赋予值,在另一函数函数中赋予值,在另一函数printprint中将它们中将它们输出。今用结构体变量作函数参数。输出。今用结构体变量作函数参数。 #include #include #define FORMAT “%dn%sn%fn%fn”struct student int num; char name20; float score3;void main() void print(struct student); struct student stu; stu.num=12345; strcpy(, LiLin); stu.sc
31、ore0=67.5; stu.score1=89; stu.score2 =78.6; print(stu);void print(struct student stu) printf(FORMAT,stu.num,, stu.score0, stu.score1,stu.score2);运行结果:运行结果:12345LiLi 67.50000089.00000078.599998例例11.6 将上题改用指向结构体变量的指针作实参。将上题改用指向结构体变量的指针作实参。#include struct student int num; char name20; float sco
32、re3; stu=12345, LiLi,67.5,89,78.6;void main() void print(struct student *);/*形参为指向结构体的指针变量形参为指向结构体的指针变量*/print(&stu); /*实参改为实参改为stu的起始地址的起始地址*/ void print(struct student *p) /*形参类型修改了形参类型修改了*/ printf(FORMAT ,p-num,p-name, p-score0,p-score1, p-score2); /*用指针变量调用各成员的值用指针变量调用各成员的值*/运行结果:运行结果:12345L
33、iLi 67.50000089.00000078.599998说明:说明:例例11.511.5值传递时值传递时(1)(1)在发生函数调用时,形参结构体变量也要占用内存空间,在发生函数调用时,形参结构体变量也要占用内存空间,接收实参结构体变量传递来的信息,因此函数之间传递结构接收实参结构体变量传递来的信息,因此函数之间传递结构体变量会带来时间和空间的巨大开销;体变量会带来时间和空间的巨大开销;(2)(2)形参与实参之间是形参与实参之间是“值传递值传递”的方式,被调函数对形参的方式,被调函数对形参结构体变量的修改并不能传递给实参,即主调函数无法得到结构体变量的修改并不能传递给实参,即主调函数无法得
34、到处理后的数据;处理后的数据;(3)(3)所以虽然语法上允许,但一般很少采用这种传递方式。所以虽然语法上允许,但一般很少采用这种传递方式。而是采用例而是采用例11.611.6传递结构体地址的方法传递结构体地址的方法,使得在调用函数与,使得在调用函数与调用函数之间共享结构体变量数据。调用函数之间共享结构体变量数据。 链表是一种最常见的数据结构,它动态地进行存储链表是一种最常见的数据结构,它动态地进行存储分配。分配。 结构体数组:必须事先定义固定的长度(元素个结构体数组:必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增数),不能适应数据动态地增减的情况。当数据增加时,可能
35、超出原先定义的元素个数;当数据减少加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。时,造成内存浪费。 链表动态地进行存储分配,可以适应数据动态地增链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)组中插入、删除数据项时,需要移动其它数据项) 链表有单向链表、双向链表、环形链表等形式。链表有单向链表、双向链表、环形链表等形式。11.7 用指针处理链表用指针处理链表图11-10链表是将若干个数据项按一定的原则连接起来的表。链表是将若干个数据项按一定的原则连接起
36、来的表。 链表组成:链表组成:(1)头指针变量头指针变量head存放首元素地址存放首元素地址,指向链表的首结点。指向链表的首结点。(2)每个结点每个结点由两个域组成:由两个域组成: 数据域数据域存储结点本身的信息。(用户有用信息)存储结点本身的信息。(用户有用信息) 指针域指针域存放下一个结点的地址。存放下一个结点的地址。(3)尾结点尾结点的指针域置为的指针域置为“NULL”,作为链表结束的标志。,作为链表结束的标志。连接原则:连接原则:(1)前一个结点指向下一个结点;前一个结点指向下一个结点; (2)只有通过前一个结点才能找到下一个结点。只有通过前一个结点才能找到下一个结点。11.7.1链表
37、概述链表概述链表结点数据可以用结构体来描述,例如链表结点数据可以用结构体来描述,例如struct studentlong num;float score;struct student *next; /* 指向下一结点指向下一结点 */ ; 其中成员其中成员num和和score用来存放结点中的有用数据(用户用来存放结点中的有用数据(用户需要用到的数据),需要用到的数据),next是指针类型的成员,它指向是指针类型的成员,它指向struct student类型数据(这就是类型数据(这就是next所在的结构体类型)所在的结构体类型)void main()struct student a,b,c,*h
38、ead,*p; /对三个结点赋值对三个结点赋值a.num=89101; a.score=89.5; b.num=89103; b.score=90;c.num=89107; c.score=85; /建立彼此的链接,形成链表建立彼此的链接,形成链表head=&a; a.next=&b;b.next=&c;c.next=NULL;p=head; /输出链表的数据信息输出链表的数据信息doprintf(%ld%5.1fn,p-num,p-score);p=p-next;while(p!=NULL);静态链表:静态链表:所有结点在程所有结点在程序中定义,没有动态申请序中定义,
39、没有动态申请空间,用完后也不能够释空间,用完后也不能够释放空间放空间11.7.2 11.7.2 简单链表简单链表运行结果:运行结果:89101 89.589103 90.089107 85.011.7.2 11.7.2 简单链表简单链表程序分析: 开始时使开始时使headhead指向指向a a结点,结点,a.nexta.next指向指向b b结点,结点,b.nextb.next指向指向c c结点,这就构成链表关系。结点,这就构成链表关系。“c.next=NULL” c.next=NULL” 的作用是使的作用是使c.nextc.next不指向任何有用的存储单元。不指向任何有用的存储单元。 在输出
40、链表时要借助在输出链表时要借助p p,先使,先使p p指向指向a a结点,然后输出结点,然后输出a a结点中结点中的数据,的数据,“p=p-next” p=p-next” 是为输出下一个结点作准备。是为输出下一个结点作准备。p-p-nextnext的值是的值是b b结点的地址,因此执行结点的地址,因此执行“p=p-next”p=p-next”后后p p就指就指向向b b结点,所以在下一次循环时输出的是结点,所以在下一次循环时输出的是b b结点中的数据。结点中的数据。11.7.3 11.7.3 处理动态链表所需的函数处理动态链表所需的函数(1) malloc函数函数 函数原型:函数原型: voi
41、d *malloc(unsigned int size) 功能功能: 在内存的动态存储区分配在内存的动态存储区分配size个字节的连续存储空间个字节的连续存储空间 。 返回值:返回值:成功,返回一个指针,该指针指向存储空间首地址,成功,返回一个指针,该指针指向存储空间首地址, 基类型为基类型为void; 失败,返回空指针(失败,返回空指针(NULL)。原因:内存空间不够。)。原因:内存空间不够。 由于返回值是空类型指针,所以在调用时必须进行强制类型由于返回值是空类型指针,所以在调用时必须进行强制类型转换,将其转换成所需的类型。转换,将其转换成所需的类型。 如:如: int *p = NULL;
42、 p = (int *)malloc(sizeof(int);库函数库函数和和提供动态地开辟和释放存储单元的提供动态地开辟和释放存储单元的有关函数:有关函数:(2) calloc函数函数函数原型:函数原型:void *calloc(unsigned n, unsigned size)功能功能: 在内存的动态存储区分配在内存的动态存储区分配n个长度为个长度为 size的连续空间的连续空间 。返回值:返回值:成功,返回所分配内存的首地址,基类型为成功,返回所分配内存的首地址,基类型为void; 失败,则返回空指针失败,则返回空指针NULL。 如:如:int *p= NULL; p = (int *
43、) calloc(10 , sizeof(int); 用calloc函数可以为一维数组开辟动态存储空间,为数组元素个数,每个元素长度为Size。(3)free函数函数 函数原型:函数原型: void free(void *p) 功能功能: 释放由释放由p指向的空间。该地址指向的空间。该地址p必须是最近一次由必须是最近一次由 malloc、 calloc、realloc函数申请成功返回的指针。函数申请成功返回的指针。 free函数无返回值函数无返回值 使用使用free前应检查该指针是否为空。前应检查该指针是否为空。 如:如:int *p = NULL; p = (int *)malloc(10
44、* sizeof(int); if ( p != NULL) free(p); p = NULL; 注意注意:free和和NULL 配对配对使用使用!(4) realloc函数函数 void *realloc(void *ptr, size_t size) 功能功能: 释放释放ptr指向的空间,并按指向的空间,并按size指定的大小重新分指定的大小重新分配空间,同时将原有数据拷贝到新分配的内存区域配空间,同时将原有数据拷贝到新分配的内存区域 。 返回值:返回值:成功,返回所分配内存的首地址;成功,返回所分配内存的首地址; 失败,则返回失败,则返回NULL。 如:如:int *p = NULL;
45、 p = malloc(10 * sizeof(int); p = realloc(p, 40 * sizeof(int);对链表的基本操作对链表的基本操作(1)创建(创建( create )链表:从无到有地建立起一个链表,即往链表:从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。关系。(2)检索(检索(scan)操作:按给定的结点索引号或检索条件,查操作:按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点,则称为检索成功;否则,找某个结点。如果找到指定的结点,则称为检索成功;否则,称为检索
46、失败。称为检索失败。(3)插入(插入(insert)操作:在结点操作:在结点ki-1与与ki之间插入一个新的结之间插入一个新的结点点k,使线性表的长度增,使线性表的长度增1。(4)删除(删除(delete)操作:删除结点操作:删除结点ki,使线性表的长度减,使线性表的长度减1。例例11.8写一个函数写一个函数creat(),建立一个有,建立一个有3个学生的单向动态链表。个学生的单向动态链表。分析建立过程:分析建立过程:设:链表结构为:设:链表结构为:struct student longnum; float score; struct student *next; ;约定约定:当输入的当输入的
47、num等于零时,表示建立过程结束。等于零时,表示建立过程结束。定义以下变量:两个指针定义以下变量:两个指针*p1 , *p2 struct student *head; /* 表头表头 */struct student *p1; /* 新建结点新建结点 */struct student *p2; /* 表尾结点表尾结点 */11.7.4 建立动态链表建立动态链表(1)创建(创建( create )链表)链表:从无到有地建立起一个链表,即往:从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。如何开辟第
48、如何开辟第1个节点?个节点?开始时:开始时:head=NULL;(1)先用)先用malloc函数开辟第函数开辟第1个节点,并使个节点,并使p1、p2指向它。指向它。(2)如果输入的)如果输入的p1-num ,则输入的是一个有效的节,则输入的是一个有效的节点,而且是第点,而且是第1个结点数据(个结点数据(n=1),令),令headp1,使,使head也也指向新开辟的结点。指向新开辟的结点。(3)这样,)这样,p1所指向的新开辟的结点就成为链表中第所指向的新开辟的结点就成为链表中第1个结点,同个结点,同时,时,p2=p1。p2=p1=(struct student*)malloc(LEN);sca
49、nf(%ld,%f,&p1-num,&p1-score);第第1个结点个结点headp1如何开辟第如何开辟第2 2个节点:个节点:(1 1)再开辟一个新结点并使)再开辟一个新结点并使p1p1指向它,接着输入该结点的数据。指向它,接着输入该结点的数据。p1=(struct student*)malloc(LEN);scanf(%ld,%f,&p1-num,&p1-score);(2 2)如果输入的)如果输入的p1-nump1-num,则应链入第个结点(,则应链入第个结点(n=2)n=2)。将。将p1p1指指向的新结点的地址赋给第向的新结点的地址赋给第1 1个结点的
50、个结点的nextnext成员。成员。(3 3)接着使)接着使,也就是使也指向刚建立的新结点。,也就是使也指向刚建立的新结点。p2p2重新指向表尾结点。重新指向表尾结点。非第一个结点非第一个结点p2-next=p1;p2=p1;如何开辟第如何开辟第2 2个节点个节点( (续续) ):如何开辟第如何开辟第3 3个节点:个节点:(1)再新开辟一个结点)再新开辟一个结点并使并使p1指向它,接着输指向它,接着输入该结点的数据。入该结点的数据。(2)如果输入的)如果输入的p1-num,则应链入第,则应链入第3个结点(个结点(n=3)。将。将p1指指向的新结点的地址赋给第向的新结点的地址赋给第2个结点的个结
51、点的next成员。成员。 p2-next=p1;(3)接着使接着使 p2=p1; 也就是使也指向刚也就是使也指向刚建立的新结点。建立的新结点。 p2p2重新指向表尾结点。重新指向表尾结点。p2=p1;非第一个结点非第一个结点p2-next=p1;(1)再开辟一个新结点并)再开辟一个新结点并使使p1指向它,接着指向它,接着输入该结点的数据。输入该结点的数据。(2)由于)由于p1-num的值的值为,此新结点不为,此新结点不应被连接到链表中应被连接到链表中. p2-next=NULL 建立链表过程至此结束,建立链表过程至此结束,p1最后所指的结点未链最后所指的结点未链入链表中,第入链表中,第3个结点
52、的个结点的next成员的值为成员的值为NULL,它不指向任何结点。它不指向任何结点。如何封尾巴:如何封尾巴:p2-next=NULLNULL建立链表的函数如下: #include #include #define NULL 0 /令令NULL代表,用它表示代表,用它表示“空地址空地址#define LEN sizeof(struct student) /令令LEN代表代表struct /student类型数据的长度类型数据的长度 struct student long num; float score; struct student *next; ;int n; /struct struct
53、studentstudent、n n为全局变量,本文件模块中各函为全局变量,本文件模块中各函数均可使用它数均可使用它struct student * creat() / 创建链表,返回表头指针创建链表,返回表头指针 struct student *head; /表头表头 struct student *p1; / 新建结点新建结点 */struct student *p2; /表尾结点表尾结点 */n = 0; /结点数为结点数为0 */head = NULL; /还没有任何结点,表头为指向空还没有任何结点,表头为指向空 */p1 = (struct student *)malloc(LEN)
54、; /创建一个新结点创建一个新结点p1 p2 = p1; /表尾表尾p2也指向也指向p1 */ scanf(%ld,%f, &p1-num, &p1-score); /读入第一个结点读入第一个结点的学生数据的学生数据 */ while(p1-num != 0) / 假设假设num=0表示输入结束表示输入结束 n = n + 1;if (n = 1) head = p1; /第一个新建结点是表头第一个新建结点是表头 elsep2-next = p1; /原表尾的下一个结点是新建结点原表尾的下一个结点是新建结点p2 = p1; /新建结点成为表尾新建结点成为表尾 p1 = (str
55、uct student *)malloc(LEN); /新建一个结点新建一个结点 scanf(“%ld,%f”, &p1-num, &p1-score); /读入新建结点的读入新建结点的 学生数据学生数据 free(p1); / 对于对于num=0的结点,未加入链表,应删除其空间的结点,未加入链表,应删除其空间 p2-next = NULL; /输入结束,表尾结点的下一个结点为空输入结束,表尾结点的下一个结点为空 return (head); /返回表头指针返回表头指针 实际上书上程序还有不完美的情况:实际上书上程序还有不完美的情况:p1 = (struct student *
56、)malloc(LEN); scanf(“%ld,%f”, &p1-num, &p1-score); 改成:改成:p1 = (struct student *)malloc(LEN); scanf(“%ld,%f”, &p1-num, &p1-score);11.7.5 输出链表输出链表 只要已知表头结点只要已知表头结点head,设一个指针变量,设一个指针变量p,先指向先指向第第1个结点个结点p=head,输出当前,输出当前p所指的结点,所指的结点,通过通过p=p-next可以找到下一个结点,从而可以输出链表的全部结点数据。可以找到下一个结点,从而可以输出链表的
57、全部结点数据。void print(struct student *head) struct student *p; /指向要输入的结点指向要输入的结点 printf(nNow, These %d records are:n, n); p = head; if (p = NULL) return;/ 不是空表不是空表 do printf(“%ld %5.1fn”, p-num, p-score); p = p-next;/指向下个结点指向下个结点 while(p != NULL); 11.7.6 对链表的删除操作对链表的删除操作 从链表中删除一个结点,分两步从链表中删除一个结点,分两步:(1)
58、找到要删除的节点()找到要删除的节点(2)删除节点,把它从链表中分离出来,撤销原有的链接关系即可。删除节点,把它从链表中分离出来,撤销原有的链接关系即可。算法:算法:设两个指针变量设两个指针变量p1、p2,(1) 开始开始p1=head,用,用p1=p1-next一直找到需要删除的结点,一直找到需要删除的结点, 设设关键字关键字num, num = p1- num代表找到。代表找到。(2) 让让p1不断移动寻找要删除的结点过程中,不断移动寻找要删除的结点过程中, p2也移动,始终指向也移动,始终指向p1的前一个结点。的前一个结点。应考虑以下情况:应考虑以下情况:1、删除的结点是第、删除的结点是
59、第1个结点。个结点。if(num=p1-num) /找到了找到了 if( p1=head) head=p1-next; /是第是第1个结点个结点要删的是第要删的是第1 1个结点,则应将个结点,则应将-赋给。赋给。指向原来的第指向原来的第2 2个结点。第个结点。第1 1个结点虽然仍存在,但它个结点虽然仍存在,但它已与链表脱离,因为链表中从头指针开始无法访问到它。已与链表脱离,因为链表中从头指针开始无法访问到它。 p-原来指向指向的结点(图中第原来指向指向的结点(图中第2个结点),个结点),现在现在-改为指向改为指向-所指向的结点(图所指向的结点(图中第中第3个结点)。所指向的结点不再是链表的一部
60、分。个结点)。所指向的结点不再是链表的一部分。2、删除的结点不是第、删除的结点不是第1个结点个结点if(num=p1-num) /找到了找到了 if( p1=head) head=p1-next; else p2-next=p1-next; 还需要考虑链表是空表(无结点)和链表中找不到要删除的结还需要考虑链表是空表(无结点)和链表中找不到要删除的结点的情况。点的情况。删除结点的函数删除结点的函数del: del: /参数是表头,和要删除的关键字。参数是表头,和要删除的关键字。struct student *del(struct student *head,long num) struct student *p1,*p2; if (head=NULL)printf(“nlist null!n”);goto end; /空表空表 p1=head; whi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026教育信息化产品市场供需状况与投资前景报告
- 2026摩托车零部件制造业市场现状供需分析及投资评估规划分析研究报告
- 2026抗菌涂层在医疗器械中的应用拓展与市场教育策略报告
- 2026急诊抢救设备智能化预警系统开发与验证报告
- 2026建筑遮阳材料智能化转型关键技术攻关与专利布局报告
- 2026建筑能效管理领域LonWorks技术渗透率与增长动力研究
- 2026建筑涂料行业碳中和路径与可持续发展战略研究报告
- 2026建筑涂料施工工艺革新对产品性能要求变化研究
- 2026建筑涂料冬季施工技术突破与北方市场开发报告
- 中医护理促进肠道健康
- 智联招聘国企笔试题库2026年答案
- 超龄劳动者用工协议
- 2025广西中考数学真题(原卷版)
- 血标本采集错误快速反应应急演练脚本及流程
- 2026年家庭服务机器人行业分析报告及未来发展趋势报告
- 初中化学九年级下册《常见的酸和碱》单元整体教学设计(教案)
- 危重新生儿工作制度
- 2026年高考地理一轮复习:40个高频考点答题模板汇编
- 菱形的判定 教学设计2025-2026学年人教版数学八年级下册
- 广州医科大学《中国近现代史纲要III》2024-2025学年期末试卷(A卷)
- 环保政策培训资料
评论
0/150
提交评论