C语言程序设计曲阜师范大学_第1页
C语言程序设计曲阜师范大学_第2页
C语言程序设计曲阜师范大学_第3页
C语言程序设计曲阜师范大学_第4页
C语言程序设计曲阜师范大学_第5页
已阅读5页,还剩87页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第九章 结构体和共用体本章要点n结构体类型定义、结构体变量定义及使用结构体类型定义、结构体变量定义及使用n结构体数组结构体数组n结构体指针结构体指针n结构体与函数结构体与函数n链表链表n共用体共用体本章学习目标 n掌握结构体类型定义、结构体变量定义、成员掌握结构体类型定义、结构体变量定义、成员引用、初始化方法引用、初始化方法n掌握用指针操作结构体和结构体数组的方法掌握用指针操作结构体和结构体数组的方法n理解结构体在函数参数传递中的应用理解结构体在函数参数传递中的应用n理解存储空间的动态分配与回收理解存储空间的动态分配与回收n理解链表的概念、掌握链表的基本操作理解链表的概念、掌握链表的基本操作n

2、理解共用体的含义、掌握共用体的使用理解共用体的含义、掌握共用体的使用3.1 应用实例 n设计超市购物系统,需要把超市内的各种商品设计超市购物系统,需要把超市内的各种商品的信息存储起来以备查询,每种商品都有多种的信息存储起来以备查询,每种商品都有多种信息信息商品编号、商品名称、商品单价等。商品编号、商品名称、商品单价等。如果把每个商品的多种信息分别存放在一些变如果把每个商品的多种信息分别存放在一些变量中,那变量数目会很多且不好管理。这时我量中,那变量数目会很多且不好管理。这时我们就需要把这些不同类型的信息组合在一个有们就需要把这些不同类型的信息组合在一个有机的整体中,以便于操作。结构体类型数据就

3、机的整体中,以便于操作。结构体类型数据就可以满足这种需要。可以满足这种需要。9.1.1 结构体类型的定义nC语言没有提供结构体类型,而是提供了结构语言没有提供结构体类型,而是提供了结构体类型的定义方法,我们在使用时需要自己定体类型的定义方法,我们在使用时需要自己定义。义。struct 结构体名结构体名 结构体成员列表结构体成员列表;n在定义结构体成员列表时,成员的定义形式为:在定义结构体成员列表时,成员的定义形式为:类型名类型名 成员名成员名;举例 n我们定义一个描述商品信息的结构体类型。我们定义一个描述商品信息的结构体类型。struct goods int number; char name

4、10; float price;nstruct goods就是结构体类型名就是结构体类型名n该结构体类型包含三个成员该结构体类型包含三个成员9.1.2 结构体变量的定义 n(1)使用结构体类型名定义变量)使用结构体类型名定义变量 struct goods int number; char name10; float price; ; struct goods g1, g2 ;存储空间示意图 n各成员按定义顺序依次存放,各成员按定义顺序依次存放,n成员的存储空间是相邻的。成员的存储空间是相邻的。n成员成员number是整型,占是整型,占4个个字节;字节;n成员成员name是字符型数组,是字符型数

5、组,占占10个字节个字节n成员成员price是实型,占是实型,占4个字个字节;节;n变量变量g1和和g2各占各占18个字节存个字节存储空间。储空间。 numbe r name price g1 9.1.2 结构体变量的定义n(2)定义结构体类型的同时定义变量)定义结构体类型的同时定义变量 struct goods int number; char name10; float price; g1, g2 ;n结构体变量结构体变量g1和和g2的定义直接跟在结构体类型的定义直接跟在结构体类型struct goods的定义之后。的定义之后。9.1.2 结构体变量的定义n(3)直接定义结构体类型变量)直

6、接定义结构体类型变量 struct int number; char name10; float price; g1, g2;n在这种定义方式下,没有给该结构体类型命名,在这种定义方式下,没有给该结构体类型命名,因此无法在其他位置定义该结构体类型的变量,因此无法在其他位置定义该结构体类型的变量,也无法将它们用作函数参数。也无法将它们用作函数参数。9.1.2 结构体变量的定义n(4)使用)使用typedefntypedef可为一个已存在的数据类型定义一个可为一个已存在的数据类型定义一个类型名。类型名。typedef int integer;n为为int类型指定一个新的类型名类型指定一个新的类型名

7、integer。typedef float real; n为为float类型指定一个新的类型名类型指定一个新的类型名eger a, b; /*a,b为为int类型变量类型变量*/real c, d; /*c,d为为float类型变量类型变量*/n注意:注意:typedef并不引入一个新的数据类型,并不引入一个新的数据类型,只是给已定义的数据类型指定一个同义词。只是给已定义的数据类型指定一个同义词。9.1.2 结构体变量的定义 typedef struct goods int number; char name10; float price; kind;n为结构体类型为结构体类型

8、struct goods起了一个新的名字起了一个新的名字kind。n注意:这里的注意:这里的kind不是结构体变量,而不是结构体变量,而是是struct goods的别名。既可以使用的别名。既可以使用struct goods去定义结构体变量,也可以使用去定义结构体变量,也可以使用kind去定义结构体变量。比如:去定义结构体变量。比如:struct goods g1;kind g2;9.1.3 结构体变量的使用n在定义了结构体变量后,访问结构体各成员的在定义了结构体变量后,访问结构体各成员的语法格式为:语法格式为:结构体变量名结构体变量名. 成员名成员名n结构体变量的成员可以像普通变量一样进行各

9、结构体变量的成员可以像普通变量一样进行各种运算和操作。例如:种运算和操作。例如:g1.number=10446;strcpy(, “apple”)g1.price=1.8;printf(“%d, %s”, g1.number, );scanf(“%f”,&g1.price); 9.1.3 结构体变量的使用n结构体变量不能作为一个整体进行输入输出等结构体变量不能作为一个整体进行输入输出等运算操作。运算操作。printf(“%d, %s, %f”, g1); /*这样是错误的这样是错误的*/结构体变量初始化 n结构体变量可以在定义的时候赋予初始值结构体变量可以在

10、定义的时候赋予初始值struct goodsint number;char name10;float price; g1=10446, “apple”, 1.8;n初始值用一对大括号括起来,并且必须按照结初始值用一对大括号括起来,并且必须按照结构体类型定义中成员的排列顺序依次给出每个构体类型定义中成员的排列顺序依次给出每个初始值。初始值。n【例【例9-1】从键盘读入一种商品的编号,】从键盘读入一种商品的编号,名称和价格信息,如果输入的商品名称名称和价格信息,如果输入的商品名称是是 “apple”,则价格打,则价格打8折。最后输出打折。最后输出打折后的信息。折后的信息。void main( )

11、struct goods int number; char name10; float price; g1; printf(“请输入商品编号、名称、单价请输入商品编号、名称、单价:n”); scanf(“%d%s%f”,&g1.number, , &g1.price); if( strcmp(, “apple”)=0) g1.price*=0.8; printf(“打折后为打折后为: %d,%s,%f ”, g1.number, , g1.price);9.2 结构体数组n以超市购物系统为例,有了结构体变量之后可以超市购物系统为例,有了

12、结构体变量之后可以方便地存储一种商品的多类信息,但超市商以方便地存储一种商品的多类信息,但超市商品种类有很多,如果为每一类商品都定义一个品种类有很多,如果为每一类商品都定义一个结构体变量也是很复杂的。这种情况我们可以结构体变量也是很复杂的。这种情况我们可以使用结构体数组,相当于批量定义多个结构体使用结构体数组,相当于批量定义多个结构体变量。变量。 9.2.1 结构体数组的定义n(1)使用结构体类型名定义数组)使用结构体类型名定义数组 struct goods int number; char name10; float price; struct goods g10;9.2.1 结构体数组的定

13、义n(2)定义结构体类型的同时定义数组)定义结构体类型的同时定义数组 struct goods int number; char name10; float price; g10;9.2.1 结构体数组的定义n(3)直接定义结构体类型数组)直接定义结构体类型数组 struct int number; char name10; float price; g10;9.2.1 结构体数组的定义n(4)使用)使用typedef typedef struct goods int number; char name10; float price; kind; kind g10;结构体数组g的存储空间示意图

14、 n以上四种方法都可以定义一个结以上四种方法都可以定义一个结构体数组构体数组g,里面含有,里面含有10个元素,个元素,g0、g1.g9。每个数组元素。每个数组元素都是一个结构体,都含有三个成都是一个结构体,都含有三个成员,例如:员,例如:g0.number=10446;strcpy(, “apple”);g0.price=1.8;g9.number=10442;strcpy(, “orange”);g9.price=1.5; g0g1g910446 “apple” 1.8 10447 “banana” 2.6 10442 “orange” 1.5 9.2.2 结构体

15、数组的初始化n在定义结构体数组时可以给每个数组元素指在定义结构体数组时可以给每个数组元素指定初始值,此时需要将每个数组元素的成员的值定初始值,此时需要将每个数组元素的成员的值分别用大括号括起来。分别用大括号括起来。 struct goods int number; char name10; float price; g3=10446, “apple”, 1.8, 10447, “banana”, 2.6, 10448, “pear”, 1.6;n【例【例9-2】统计商品信息】统计商品信息void main( ) struct goods int number; char name10; flo

16、at price; g10; int i, max, min; float average=0.0; for(i=0;i10;i+) printf(输入商品编号、名称、单价输入商品编号、名称、单价:n); scanf(%d%s%f, &gi.number, ,gi.price); max=min=0; for(i=0;igmax.price) max=i; if(gi.price结构体成员名结构体成员名例如:例如:p-number p-namen【例【例9-3】将程序】将程序9-1改为通过指针变量对结构改为通过指针变量对结构体进行操作。体进行操作。void main( )

17、 struct goods int number; char name10; float price; g1, *p; p=&g1; /*指针需指向某一个结构体变量后才能使指针需指向某一个结构体变量后才能使用用*/ printf(“请输入商品编号、名称、单价请输入商品编号、名称、单价:n”); scanf(“%d%s%f”,&p-number, p-name, &p-price); if( strcmp(p-name, “apple”)=0 ) p-price*=0.8; printf(“打折后打折后:%d,%s,%fn”,(*p).number, (*p).name,

18、 (*p).price);&g1pg11111 apple 2.3 9.3.2 指向结构体数组的指针n定义一个结构体类型的指针变定义一个结构体类型的指针变量指向一个结构体数组,这样量指向一个结构体数组,这样可以通过指针变量的算术运算可以通过指针变量的算术运算来访问结构体数组中的每个元来访问结构体数组中的每个元素。素。struct goods g10,*p;p=g;n此时,指针变量指向的是结构此时,指针变量指向的是结构体数组的第一个元素。体数组的第一个元素。 g0g1pp+110446 “apple” 1.8 10447 “banana” 2.6 . . . n【例【例9-4】统计】统计

19、10种商品价格最高和最低的,种商品价格最高和最低的,以及商品的平均价格。要求使用结构体指针实以及商品的平均价格。要求使用结构体指针实现。现。void main( ) struct goods int number; char name10; float price; ; struct goods g10,*p,*pmax,*pmin; int i; float average=0.0; p=g; /指针指针p指向了数组的首地址指向了数组的首地址 printf(“input information of the goods:n”); for(i=0;inumber, p-name, &p

20、-price); p+; n p=g; pmax=pmin=g; for(i=0;ipricepmax-price) pmax=p; if(p-priceprice) pmin= p; average=average+ p-price; p+; average=average/10; printf(“the max price is:%d,%s,%fn”, pmax-number, pmax-name, pmax-price); printf(“the min price is:%d,%s,%fn”, pmin-number,pmin-name,pmin-price); printf(“the

21、 average price is:%fn”, average); 9.4 结构体与函数 n通过函数参数在两个函数之间传递一个结构体通过函数参数在两个函数之间传递一个结构体通常有以下三种方式。通常有以下三种方式。n结构体变量的成员作函数实参结构体变量的成员作函数实参 n结构体变量作函数参数结构体变量作函数参数 n指向结构体的指针作函数参数指向结构体的指针作函数参数 9.4.1 结构体变量的成员作函数实参n结构体的一个或多个成员可作为独立的函数参结构体的一个或多个成员可作为独立的函数参数进行传递。数进行传递。n注意:如果结构体成员为数组或指针类型,将注意:如果结构体成员为数组或指针类型,将其作为

22、实参,则实参与形参之间传递的数据为其作为实参,则实参与形参之间传递的数据为地址。实参和形参便指向同一个对象,被调函地址。实参和形参便指向同一个对象,被调函数执行时,可以通过形参访问其所指向的对象,数执行时,可以通过形参访问其所指向的对象,如果被调函数利用形参修改了其所指向的对象如果被调函数利用形参修改了其所指向的对象的内容,实际上也就是实参所指向的对象的内的内容,实际上也就是实参所指向的对象的内容改变了。容改变了。9.4.1 结构体变量的成员作函数实参#include #include struct student int num; char name20; char sex; int sco

23、re3;void fun(int num, char name , char sex, int s ) num=10447; strcpy(name, lisi); sex=W; s0=60; s1=60; s2=60;void main( ) struct student stu; stu.num=10446; strcpy(, zhangsan); stu.sex= M; stu.score0=78; stu.score1=96; stu.score2=86; printf(调用函数前数据为:调用函数前数据为:%d,%s,%c,%d,%d,%dn, stu.num, stu

24、.name, stu.sex, stu.score0, stu.score1, stu.score2 ); fun(stu.num, , stu.sex, stu.score); printf(调用函数后数据为:调用函数后数据为:%d,%s,%c,%d,%d,%dn, stu.num, , stu.sex, stu.score0,stu.score1, stu.score2 );程序执行后输出结果为:程序执行后输出结果为:调用函数前数据为:调用函数前数据为:10446,zhangsan,M,78,96,86调用函数后数据为:调用函数后数据为:10446,lisi

25、,M,60,60,609.4.2 结构体变量作函数参数n可以用结构体变量作实参,对应的形参应该是可以用结构体变量作实参,对应的形参应该是相同类型的结构体变量。实参将各个成员的值相同类型的结构体变量。实参将各个成员的值传递给形参的对应成员。被调函数执行过程中,传递给形参的对应成员。被调函数执行过程中,形参值发生了改变,实参值不会相应变化。形参值发生了改变,实参值不会相应变化。9.4.2 结构体变量作函数参数#include #include struct student int num; char name20; char sex; int score3;void fun(struct stud

26、ent stu) stu.num= 10447; strcpy(, “lisi”); stu.sex=W; stu.score0=60; stu.score1=60; stu.score2=60;9.4.2 结构体变量作函数参数void main() struct student stu; stu.num=10446; strcpy(, “zhangsan”); stu.sex= M; stu.score0=78; stu.score1=96; stu.score2=86; printf(调用函数前为:调用函数前为:%d,%s,%c,%d,%d,%dn, stu

27、.num, , stu.sex, stu.score0, stu.score1, stu.score2 ); fun(stu); printf(调用函数后为:调用函数后为:%d,%s,%c,%d,%d,%dn, stu.num, , stu.sex, stu.score0, stu.score1 , stu.score2 ); 程序执行后输出结果为:程序执行后输出结果为:调用函数前数据为:调用函数前数据为:10446,zhangsan,M,78,96,86调用函数后数据为:调用函数后数据为:10446,zhangsan,M,78,96,869.4.3 指向结构体

28、的指针作函数参数n在使用指向结构体的指针做实参时,对应的形在使用指向结构体的指针做实参时,对应的形参也应定义为结构体指针类型。实参传递给形参也应定义为结构体指针类型。实参传递给形参的是一个结构体的地址,实参和形参指向同参的是一个结构体的地址,实参和形参指向同一个结构体,在被调函数执行过程中,通过形一个结构体,在被调函数执行过程中,通过形参对该结构体做的任何改变,也相当于改变了参对该结构体做的任何改变,也相当于改变了实参所指向的结构体的值。实参所指向的结构体的值。9.4.3 指向结构体的指针作函数参数#include #include struct student int num; char n

29、ame20; char sex; int score3;void fun(struct student *p) p-num= 10447; strcpy(p-name, “lisi”); p-sex=W; p-score0=60; p-score1=60; p-score2=60;&stu&stu实参pstu 形参p9.4.3 指向结构体的指针作函数参数void main( ) struct student stu, *p; stu.num=10446; strcpy(, “zhangsan”); stu.sex= M; stu.score0=78; stu.s

30、core1=96; stu.score2=86; p=&stu; printf(调用函数前为:调用函数前为:%d,%s,%c,%d,%d,%dn, stu.num, , stu.sex, stu.score0, stu.score1, stu.score2 ); fun(p); /*或者或者fun(&stu);*/ printf(调用函数后为:调用函数后为:%d,%s,%c,%d,%d,%dn, stu.num, , stu.sex, stu.score0, stu.score1,stu.score2 );程序执行后输出结果为:程序执行后输出结果

31、为:调用函数前数据为:调用函数前数据为:10446,zhangsan,M,78,96,86调用函数后数据为:调用函数后数据为:10447,lisi,W,60,60,609.5 链表n链表是一种能够灵活扩展长度的动态数据结构链表是一种能够灵活扩展长度的动态数据结构n链表由多个结点通过指针的指向连接在一起,链表由多个结点通过指针的指向连接在一起,每个结点都有独立的存储空间,一个结点的存每个结点都有独立的存储空间,一个结点的存储空间是连续的,但多个结点的存储空间可以储空间是连续的,但多个结点的存储空间可以是不连续的。每个结点的存储空间可以分为两是不连续的。每个结点的存储空间可以分为两部分:数据域和指

32、针域。数据域用于存放用户部分:数据域和指针域。数据域用于存放用户需要处理的数据,指针域用于存放下一个结点需要处理的数据,指针域用于存放下一个结点的地址。我们就可以从链表的第一个结点开始,的地址。我们就可以从链表的第一个结点开始,依次访问链表中的每个结点。依次访问链表中的每个结点。9.5 链表n为了方便找到头结点,对于每个链表,我们都为了方便找到头结点,对于每个链表,我们都会定义一个称为会定义一个称为“头指针头指针”的指针变量,该指的指针变量,该指针变量内存放的是链表头结点的地址,也就是针变量内存放的是链表头结点的地址,也就是头指针指向链表的头结点。头指针指向链表的头结点。n链表的最后一个结点的

33、指针域存放的是空指针,链表的最后一个结点的指针域存放的是空指针,表示链表到此结束。空指针可以用表示链表到此结束。空指针可以用C语言定义语言定义的符号常量的符号常量NULL来表示(在来表示(在C语言中符号常语言中符号常量量NULL被定义为被定义为0)。)。 9.5 链表n以超市商品管理为例,使用链表来存放商品信以超市商品管理为例,使用链表来存放商品信息更为方便,因为商品的种类数目是不断变化息更为方便,因为商品的种类数目是不断变化的。的。n定义结构体类型如下:定义结构体类型如下:struct goods char name10; float price; struct goods *next;9.

34、5.1 静态链表n静态链表指的是链表中的各个结点都是在程序静态链表指的是链表中的各个结点都是在程序中事先定义好的,编译器会分配每个结点的存中事先定义好的,编译器会分配每个结点的存储空间,不需要在程序执行时动态分配结点存储空间,不需要在程序执行时动态分配结点存储空间。链表的长度是固定的。储空间。链表的长度是固定的。 n【例【例9.8】建立一个链表,用来存储苹果、香蕉、】建立一个链表,用来存储苹果、香蕉、桃子这三种水果的名称和价格信息。桃子这三种水果的名称和价格信息。struct goods char name10; float price; struct goods *next;void mai

35、n( ) struct goods g1,g2,g3,*p,*head; strcpy(, ”apple”); g1.price=1.8; strcpy(, ”banana”); g2.price=2.6; strcpy(, ”pear”); g3.price=1.6; head=&g1; g1.next=&g2; g2.next=&g3; g3.next=NULL; p=head; while(p!=NULL) printf(“%s,%.2fn”,p-name,p-price); p=p-next; 9.5.2 动态链表n动态

36、链表是指链表中的各个结点的存储空间是动态链表是指链表中的各个结点的存储空间是在程序运行期间动态分配的,结点获得存储空在程序运行期间动态分配的,结点获得存储空间后才可以存储信息。结点数目即链表的长度间后才可以存储信息。结点数目即链表的长度是可以不断变化的。这样可以灵活的根据信息是可以不断变化的。这样可以灵活的根据信息存储的需要添加或删除结点。存储的需要添加或删除结点。nC语言函数库提供了一些完成空间分配与回收语言函数库提供了一些完成空间分配与回收的函数。的函数。 空间分配与回收函数n(1)malloc函数函数n功能:在内存中分配一块大小为功能:在内存中分配一块大小为size字节的

37、字节的连续存储空间。连续存储空间。n调用形式为:调用形式为:void * malloc(unsigned int size);n当为新结点分配一块空间时,结点中存放的当为新结点分配一块空间时,结点中存放的数据应该是结构体类型的,所以需要对返回数据应该是结构体类型的,所以需要对返回值进行强制类型转换,值进行强制类型转换,struct goods *p;p=( struct goods * ) malloc( sizeof(struct goods) ); 空间分配与回收函数n(2)calloc函数函数n功能:在内存中分配功能:在内存中分配n块,每块大小为块,每块大小为size字字节

38、的连续空间节的连续空间n函数调用形式为:函数调用形式为:void * calloc(unsigned int n, unsigned int size); 空间分配与回收函数n(3)free函数函数n功能:释放指针变量功能:释放指针变量p所指向的内存块,使所指向的内存块,使这块区域可以被其他数据使用。这块区域可以被其他数据使用。n函数调用形式为:函数调用形式为:void free(void *p); 建立和输出链表n使用使用malloc函数,依次为每个结点分配存储空函数,依次为每个结点分配存储空间,并将这些结点通过指针连接起来形成一个间,并将这些结点通过指针连接起来

39、形成一个链表,最后从链表的第一个结点开始输出每个链表,最后从链表的第一个结点开始输出每个结点的内容。结点的内容。 建立和输出链表n【例【例9.9】依次输入每种商品的名称和单价,当】依次输入每种商品的名称和单价,当输入的商品名为输入的商品名为“end”时,表示输入结束。利时,表示输入结束。利用输入的商品信息建立链表,然后输出链表的用输入的商品信息建立链表,然后输出链表的内容。内容。#include #include #include struct goods char name10; float price; struct goods *next; 建立和输出链表st

40、ruct goods * CreateList( ) struct goods *head=NULL,*p1, *p2; int n=0; p1=p2=( struct goods * ) malloc( sizeof(struct goods) ); scanf(“%s%f ”, p1-name, &p1-price); p1-next=NULL; while(strcmp(p1-name, “end”)!=0) n=n+1; if(n=1) head=p1; else p2-next=p1; p2=p1; p1=( struct goods * ) malloc( sizeof(s

41、truct goods) ); scanf(“%s%f”,p1-name, &p1-price); p1-next=NULL; free(p1); return head; 建立和输出链表void PrintList(struct goods * head) struct goods *p; p=head; while(p!=NULL) printf(“%s,%.2fn”,p-name,p-price); p=p-next; void main( ) struct goods * head; printf(“请输入商品名称、单价,名称为请输入商品名称、单价,名称为end表

42、示结束输入:表示结束输入:n”); head=CreateList( ); printf(“输出链表,商品信息如下:输出链表,商品信息如下:n”); PrintList(head); 建立和输出链表n程序运行时的情况:程序运行时的情况:请输入每个商品的名称、单价,名称为请输入每个商品的名称、单价,名称为end表示结束输入:表示结束输入:apple 1.8banana 2.6pear 1.6orange 1.2end 0输出链表,商品信息如下:输出链表,商品信息如下:apple,1.80banana,2.60pear,1.60orange,1.20程序执行过程n第一步:头指针第一步

43、:头指针head暂时内容为空值,不指向暂时内容为空值,不指向任何地方,即此时链表为空链表。任何地方,即此时链表为空链表。程序执行过程n第二步:建立第一个结点第二步:建立第一个结点n利用利用malloc函数申请第一块内存区域,假设函数申请第一块内存区域,假设该存储空间地址值为该存储空间地址值为09403,存储第一种商,存储第一种商品信息品信息“apple” 和和“1.8” 。 指针指针p1、p2都都指向该结点。指向该结点。 程序执行过程n第三步:第一个结点插入链表第三步:第一个结点插入链表n进入进入while循环循环体的第一次执行,由于循环循环体的第一次执行,由于n等于等于1,所以执行,所以执行

44、head=p1,即,即head头指针头指针指向第一个结点。指向第一个结点。程序执行过程n第四步:建立第二个结点第四步:建立第二个结点 n执行执行p1=( struct goods * ) malloc( sizeof(struct goods) ); 利用利用malloc函函数在内存中开辟第二块内存空间,存储第二数在内存中开辟第二块内存空间,存储第二种商品信息,假设存储空间地址为种商品信息,假设存储空间地址为09528,指针指针p1指向这个结点。指向这个结点。程序执行过程n第五步:第二个结点插入链表第五步:第二个结点插入链表n进入第二次进入第二次while循环,由于循环,由于n等于等于2,执行

45、,执行p2-next=p1; 新申请的结点连接到了已有链新申请的结点连接到了已有链表后面。然后执行表后面。然后执行p2=p1,p2指针又一次指指针又一次指向了当前链表的最后一个结点。向了当前链表的最后一个结点。程序执行过程n依次类推,依次类推,p1始终指向新建立的结点,始终指向新建立的结点,p2指向指向当前链表的最后一个结点,执行当前链表的最后一个结点,执行p2-next=p1将新建立的结点连接到已有链表的最后一个结将新建立的结点连接到已有链表的最后一个结点的后面。当输入点的后面。当输入“end”时循环语句结束。时循环语句结束。n循环退出后,执行循环退出后,执行p2-next=NULL;使链表

46、的使链表的最后一个结点的最后一个结点的next成员值为空指针。表示链成员值为空指针。表示链表的结束。表的结束。 查找链表结点n从链表中找出其成员值等于给定值的结点。这从链表中找出其成员值等于给定值的结点。这时,需要从链表的第一个结点开始逐个遍历每时,需要从链表的第一个结点开始逐个遍历每个结点。如果找到匹配的结点则返回指向该结个结点。如果找到匹配的结点则返回指向该结点的指针,如果遍历到最后一个结点仍没找到点的指针,如果遍历到最后一个结点仍没找到匹配结点则返回空指针。匹配结点则返回空指针。 查找链表结点#include #include #include struct

47、goods char name10; float price; struct goods *next;struct goods * SearchList(struct goods *head, char * name) struct goods *p; p=head; while(p) if( strcmp(p-name, name)=0) return p; p=p-next; return NULL; 查找链表结点void main( ) struct goods * head,*p; char name10; printf(“建立链表,依次输入每个商品的名称、单价:建立链表

48、,依次输入每个商品的名称、单价:n”); head=CreateList( ); printf(“输入要查找的商品名称:输入要查找的商品名称:”); scanf(“%s”, name); p= SearchList (head, name); if(p!=NULL) printf(“商品已查找到:商品已查找到:%s,%.2fn”,p-name, p-price); else printf(“没找到该商品的信息没找到该商品的信息n”); 删除链表结点n删除链表中某个结点,通常要进行以下三个步删除链表中某个结点,通常要进行以下三个步骤:骤:n(1)首先找到要删除的结点;)首先找到要删

49、除的结点;n(2)使该结点的前一个结点的)使该结点的前一个结点的next成员指成员指向要删除结点的下一个结点,从而绕过被删向要删除结点的下一个结点,从而绕过被删除结点;除结点;n(3)最后使用)最后使用free函数释放掉被删除结点的函数释放掉被删除结点的存储空间。存储空间。 删除链表结点n在第(在第(1)步中,我们可以定位到要删除结点)步中,我们可以定位到要删除结点并用指针指向它,但是为了进行第(并用指针指向它,但是为了进行第(2)步操)步操作,我们需要找到被删除结点的前一个结点。作,我们需要找到被删除结点的前一个结点。所以在进行第(所以在进行第(1)步操作时,我们将使用两)步操

50、作时,我们将使用两个指针,指针个指针,指针p1用于指向当前结点,指针用于指向当前结点,指针p2用用于指向当前结点的前一个结点。当于指向当前结点的前一个结点。当p1指向被删指向被删除结点时,除结点时,p2就刚好指向被删除结点的前一个就刚好指向被删除结点的前一个结点。结点。n【例【例9.11】在存储商品信息的链表中删除给定】在存储商品信息的链表中删除给定名称的商品。名称的商品。struct goods * DeleteList(struct goods *head,char * name) struct goods *p1, *p2; p1=head; while(p1!=NULL &st

51、rcmp(p1-name, name)!=0) p2=p1; p1=p1-next; if(p1=NULL) return head; /*被删除结点没找到被删除结点没找到*/ else if(p1=head) head=p1-next; /*被删除结点是链表第一个结点,需要改变被删除结点是链表第一个结点,需要改变头指针值头指针值*/ else p2-next=p1-next; /*被删除结点是其它结点被删除结点是其它结点*/ free(p1); return head; void main( ) struct goods * head; char name10; printf(“建立链表,依

52、次输入每个商品的名称、单价:建立链表,依次输入每个商品的名称、单价:n”); head=CreateList( ); printf(“输出链表,商品信息如下:输出链表,商品信息如下:n”); PrintList(head); printf(“输入要删除的商品名称:输入要删除的商品名称:”); scanf(“%s”,name); head= DeleteList (head,name); printf(“删除后,链表中商品信息如下:删除后,链表中商品信息如下:n”); PrintList(head);执行过程n第一步:找到待删除结点第一步:找到待删除结点n从第一个结点开始查到要删除的结点,从第一

53、个结点开始查到要删除的结点,p1指指向当前检查的结点,此时向当前检查的结点,此时p2指向当前结点的指向当前结点的前一个结点。指针前一个结点。指针p1,p2同时向后移动,直同时向后移动,直到到p1指向待删除结点。(假设要删除商品指向待删除结点。(假设要删除商品banana的信息)的信息)n第二步:从链表中摘除一个结点第二步:从链表中摘除一个结点n执行执行p2-next=p1-next; 使得待删除结点的使得待删除结点的前一个结点的前一个结点的next指向待删除结点的下一个指向待删除结点的下一个结点,相当于绕过了待删除结点。结点,相当于绕过了待删除结点。n第三步:使用第三步:使用free函数释放函

54、数释放banana结点占用的结点占用的存储空间。存储空间。 插入链表结点n向链表中插入一个新结点,首先要为新结点分向链表中插入一个新结点,首先要为新结点分配存储空间,把数据存入结点中,然后把新结配存储空间,把数据存入结点中,然后把新结点插入到链表中指定位置。点插入到链表中指定位置。n插入结点通常要进行以下三个步骤:插入结点通常要进行以下三个步骤: n (1)首先找到)首先找到“插入点插入点”后的结点;后的结点;n (2)使新结点的)使新结点的next成员指向成员指向“插入点插入点”后的结点;后的结点;n (3)使)使“插入点插入点”前的结点的前的结点的next成员指成员指向新结点

55、。向新结点。 新结点的插入点 n假设在存储商品信息的链表中,各结点按照商假设在存储商品信息的链表中,各结点按照商品单价从低到高依次连接,插入新结点后仍要品单价从低到高依次连接,插入新结点后仍要保持这种排列顺序。这样就可以确定新结点的保持这种排列顺序。这样就可以确定新结点的插入点。插入点。n【例【例9.12】在存储商品信息的链表中插入一种】在存储商品信息的链表中插入一种新商品的信息(按单价从低到高排列)。新商品的信息(按单价从低到高排列)。struct goods * InsertList (struct goods *head,char * name ,float price) struct

56、goods *p1, *p2, *newnode; newnode=( struct goods * ) malloc( sizeof(struct goods) ); strcpy(newnode -name, name); newnode -price=price; p1=head; while(p1!=NULL & p1-pricenext; if(head=NULL) /*链表为空链表链表为空链表*/ head= newnode; newnode -next=NULL; return head; if(p1=head) /*在链表的第一个结点前插入新结点在链表的第一个结点前插入

57、新结点*/ head=newnode; newnode -next=p1; else /*在链表的其它位置插入新结点在链表的其它位置插入新结点*/ p2-next=newnode; newnode-next=p1; return head;程序执行过程n第一步第一步 建立新结点建立新结点n新申请开辟一个结点,存储西瓜商品的信息,新申请开辟一个结点,存储西瓜商品的信息,用用newnode指针指向该结点。指针指向该结点。n第二步第二步 将新结点插入链表将新结点插入链表n从链表的第一个结点开始查找插入点。使用从链表的第一个结点开始查找插入点。使用两个指针变量两个指针变量p1和和p2,p1指向当前检查

58、的结指向当前检查的结点,点,p2指向当前结点的前一个结点。指向当前结点的前一个结点。p1、p2同时向后移动,直到同时向后移动,直到p1指向苹果商品结点。指向苹果商品结点。新结点插入在新结点插入在p1、p2所指结点之间。所指结点之间。n然后,执行然后,执行p2-next=newnode; newnode-next=p1; 将新结点插入到链表中,放置在苹将新结点插入到链表中,放置在苹果商品结点前面。果商品结点前面。将新结点插入链表 9.6 共用体n为了节省空间,希望几个不同类型的数据共用一块存为了节省空间,希望几个不同类型的数据共用一块存储空间,该存储空间某一时刻只能由一个数据使用,储空间,该存储

59、空间某一时刻只能由一个数据使用,这种效果可以用共用体来实现,一个共用体所占存储这种效果可以用共用体来实现,一个共用体所占存储空间长度等于其最长的成员的存储空间长度,空间长度等于其最长的成员的存储空间长度,n定义形式:定义形式:union 共用体名共用体名 成员表列成员表列其中每个成员的定义形式为其中每个成员的定义形式为类型名类型名 成员名成员名;9.6.1 共用体变量的定义n(1)使用共用体类型名定义变量)使用共用体类型名定义变量 union goods int number; char name; float price; union goods g1, g2 ;numbernamepric

60、e 9.6.1 共用体变量的定义n(2)在定义共用体类型的同时定义变量)在定义共用体类型的同时定义变量 union goods int number; char name; float price; g1, g2 ;9.6.1 共用体变量的定义n(3)直接定义共用体类型变量)直接定义共用体类型变量 union int number; char name; float price; g1, g2;9.6.1 共用体变量的定义n(4)使用)使用typedeftypedef union goods int number; char name; float price; kind;union goods g1;或者或者kind g2;9.6.2 共用体变量的使用n使用方式为:使用方式为:共用体变量名共用体变量名.成员名成员名n共用体变量的成员像普通变

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论