C语言程序设计案例教程(下篇共上中下3篇)_第1页
C语言程序设计案例教程(下篇共上中下3篇)_第2页
C语言程序设计案例教程(下篇共上中下3篇)_第3页
C语言程序设计案例教程(下篇共上中下3篇)_第4页
C语言程序设计案例教程(下篇共上中下3篇)_第5页
已阅读5页,还剩255页未读 继续免费阅读

下载本文档

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

文档简介

大连理工大学出版社C语言程序设计案例教程项目七学生成绩单制作教学目的:通过本项目的学习,要求了解结构型、链表、共用型和枚举型数据的特点,熟练掌握结构型的定义方法,结构型变量、数组、指针变量的定义、初始化和成员的引用方法;掌握简单链表的基本操作原理和应用;掌握共用型和枚举型的定义方法及对应变量的定义与引用;掌握用户自定义类型的定义和使用。学习本项目内容可以为今后学习数据结构中的链表创建和使用打下基础。教学内容

结构型类型的定义结构型变量的定义和引用结构体变量成员的引用项目七学生成绩单制作共用体类型的定义共用体变量的定义和引用枚举类型的定义枚举型变量的定义和引用结构体枚举型共用体重点和难点重点:(1)结构型、共用型、枚举型数据的特点和定义(2)结构型变量、数组、指针变量的定义、初始化和成员引用方法(2)共用型和枚举型变量的定义和引用方法难点:1、嵌套的结构体数据的处理

2、用结构体解决链表问题(建立、插入、删除和查询。)项目七学生成绩单制作任务1用结构体数组进行学生信息处理辅导员张老师在使用小王设计的程序时,发现如果要存储具有不同数据类型的数据结构时,如在学生信息中不只包括学生成绩数据,还包括学生的学号、等其他类型的数据,使用数组无法完成不同类型数据的存储,本任务引入结构体的概念实现对不同类型的学生信息数据的访问和计算,完善了原来的程序,帮助张老师解决了该问题。1)问题情景与实现/*功能:用结构体数组进行学生信息处理 */

#include<string.h>

#include<stdio.h>

#defineN3

structstudent

{

longnumber;

floatscore[3];

}stu[N];

voidmain()

{ inti;

printf(“请输入学生信息:\n”);

for(i=0;i<N;i++)

{项目七学生成绩单制作

scanf(“%ld,%f,%f,%f”,&stu[i].number,&stu[i].score[0],

&stu[i].score[1],

&stu[i].score[2]);

}

printf(“学号

\t语文\t数学\t英语\n”);

for(i=0;i<N;i++)

{

printf(“%ld\t%f\t%f\t%f\n”,stu[i].number,stu[i].score[0],stu[i].score[1],

stu[i].score[2]);

}}编译、连接、和运行程序。程序运行后,屏幕显示:项目七学生成绩单制作请输入学生信息:

1001,60,70,801002,80,70,601003,65,70,75学号

语文

数学

英语

1001 60.000000 70.000000 80.0000001002 80.000000 70.000000 60.0000001003 65.000000 70.000000 75.0000002)相关知识要完成上面的任务,小王必须要能熟练掌握结构型的定义方法,结构型变量、数组的定义、初始化和成员的引用方法等知识点。项目七学生成绩单制作7.1结构体类型前面我们学习过了基本数据类型,例如:short、long、int、float、double、char等,这些基本数据类型都是系统已经定义好的,用户可以直接使用它们。但现实世界是复杂的,在我们的日常生活中有很多的表格,各表格之间又有关联。因此用户需要自己定义数据类型,用户自己定义的数据类型一旦定义好之后,就可以像使用系统类型一样使用它。7.1.1结构体的实例

例如:对一个新生进行入学登记时,就需要填一张表格,填写的内容包括姓名、性别、学号、年龄、家庭住址、联系电话、总分等多个数据项,其中姓名是字符串型(可以用字符数组来表示),性别是字符型(用m表示男性、用f表示女性),年龄是整型,总分是实型。7.1

结构体类型—7.1.1简单的C程序7.1

结构体类型—7.1.1简单的C程序学生信息登记表7.1结构体类型—7.1.1简单的C程序这些数据项之间关系紧密,每一个学生通过姓名、性别、学号、年龄、家庭地址、联系电话、总分等属性构成一个整体反映一个学生的基本情况。如果将姓名、性别、学号、年龄、家庭地址、联系电话、总分分别定义为互相独立的简单变量,难以反映它们之间的内在联系。为了方便处理此类数据,常常把这些关系密切但类型不同的数据项组织在一起,即“封装”起来,并为其取一个名字,在C语言中就称其为结构体(也人称为构造体),结构体是用户自定义数据类型的一种。结构体类型定义的一般形式:

struct结构型名{数据类型标识符成员1;数据类型标识符成员2;

数据类型标识符成员n;};请读者注意结构体定义语句的右花括号后面用分号(;)做语句结束标记。7.1结构体类型7.1.2结构体类型的定义7.1结构体类型—7.1.2简单的C程序结构体型定义实例例如:为了存放一个人的姓名、性别、年龄、工资,可以定义如下的结构型:

structperson{

charname[10];

charsex;

intage;

floatwage;};

/*这个名为person的结构型共含有4个成员*/7.1结构体类型—7.1.2简单的C程序结构型嵌套定义

【例7.1】一开始所讲的例题中的birthday类型和person类型。

structbirthday/*定义含有3个整型成员的结构型birthday*/

{

intyear;

intmonth;

intday;

};

structperson/*定义含有4个成员的结构型person*/

{

charname[20];

charsex;

structbirthdaybir;/*该成员的数据类型是结构型*/

floatwage;

};7.2结构体变量的定义和引用1.先定义结构型,后定义变量

例如:为学生信息定义2个变量x和y,程序段如下:

structstudent

{

longnumber;

charname[20];

charsex;

floatscore[3];

};

structstudentx,y;在定义变量的同时,可以变量赋初值,例如上例中的定义语句可以改写如下:structstudentx={100001L,”Tom”,’m’,{86,94,89}},

y={100002L,”Lucy”,’f’,{78,88,45}};7.2.1结构型变量的定义和初始化7.2结构体变量的定义和引用—7.2.1结构型变量的定义和初始化

2.定义结构型的同时定义变量例如:为学生信息定义2个变量x和y,并给他们赋初值,程序段如下:

structstudent

{

longnumber;

charname[10];

charsex;

floatscore[3];

}

x={100001L,”Tom”,’m’,{86,94,89}},

y={100002L,”Lucy”,’f’,{78,88,45},};这种方法是将类型定义和变量定义同时进行。以后仍然可以使用这种结构型来定义其它的变量。7.2结构体变量的定义和引用—7.2.1结构型变量的定义和初始化

3.定义无名称的结构型的同时定义变量7.2结构体变量的定义和引用—7.2.1结构型变量的定义和初始化

例如:为学生信息定义2个变量x和y,并给它们赋初值,程序段如下:

struct{longnumber;

charname[10];

charsex;

floatscore[3];

}

x={100001L,”Tom”,’m’,{86,94,89}},

y={100002L,”Lucy”,’f’,{78,88,45},};这种方法是将类型定义和变量定义同时进行,但结构型的名称省略,以后将无法使用这种结构型来定义其它变量,建议尽量少用。7.2结构体变量的定义和引用结构型变量成员的引用方法结构型变量成员地址的引用方法结构型变量地址的引用方法7.2.2结构型变量成员的引用结构型变量成员的引用格式如下:

※结构型变量名.成员名其中的“.”称为成员运算符,其运算级别是最高的,和圆括号运算符“()”、下标运算符“[]”是同级别的,运算顺序是自左向右。如果某个结构型变量的成员数据类型又是一个结构型,则其成员的引用方法如下:

※外层结构型变量.外层成员名.内层成员名7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用1.结构型变量成员的引用方法7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用

【例7.2】求Tom的三门课程的成绩总分,并在显示器显示出来(使用结构型变量成员的引用)。

#include”string.h”

structstudent

{

longnumber;

charname[10];

charsex;

floatscore[3];

};

main()

{

structstudentstu1;

/*定义student类型的变量stu1*7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用stu1.number=100001L;/*给结构型变量stu1的成员number赋值*/strcpy(;”Tom”);/*给结构型变量stu1的成员name[]赋值*/stu1.sex=’f’;/*给结构型变量stu1的成员sex赋值*/stu1.score[0]=89;/*给结构型变量stu1的成员score[]赋值*/stu1.score[1]=91;stu1.score[2]=86;printf(“%s的总分是:%f\n”,,stu1.score[0]+stu1.score[1]+stu1.score[2]);}程序运行后,屏幕显示:结构型的变量成员地址引用格式如下:

※结构型的变量名.成员名存放结构型变量成员地址的指针变量类型必须和该成员的类型相同。7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用

【例7.4】结构型变量成员地址引用

#include“string.h”/*程序中使用了字符串处理函数*/sturctstudent2/*定义student2结构型*/

{

longnumber;

charname[10];

}2.结构型变量成员地址的引用方法7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用main(){structstudent2x;/*定义student2类型的变量x*/

long*p_number;/*定义能指向结构型student成员number的指针变量*/

char*p_name;/*定义能指向结构型student成员namer的指针变量*/

p_number=&x.number;/*让指针变量指向结构型变量x的成员*/*p_number=100001L;/*用指针变量给结构型变量x的所有成员赋值*/strucpy(p_name,”zhongxin”);

printf(“number=%1dname=%s\n”,*p_number,*p_name);/*用指针变量输出结构型变量x所有成员的值*/}从这个例子可以看出,使用指向结构型变量成员的指针变量来引用成员的方法比较繁琐,可以直接使用结构型变量的指针成员来引用成员。具体使用方法请参看第7章7.4节。7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用

程序运行后,屏幕显示:结构型变量地址的引用格式如下:

&结构型变量名例如:借用例7.4中的结构型structstudent2:structstudent2y,*sty=&y;存放结构型变量地址的指针变量必须是类型相同的结构型指针,关于如何使用结构型变量地址的例子请参见7.4节中介绍的指向结构型数据的指针变量。7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用3.结构型变量地址的引用方法在实际应用中,我们经常要处理的是具有相同数据结构的一个群体。比如一批书,所有员工的通信地址,一个班级的学生等。由相同结构类型变量组成的数组,称为结构型数组。例如,全班有40人,在总成绩单上每人占一行,每行的内容包括学号、姓名、3门功课的成绩、平均分、名次,这样一个总成绩单就可以用结构型数组表示。7.2结构体变量的定义和引用—7.2.2结构型变量成员的引用7.3结构型数组的定义和引用

先定义结构型,然后再定义结构型数组并赋初值定义结构型的同时定义数组并赋初值定义无名称的结构型的同时定义数组并赋初值7.3.1结构型数组的定义和初始化7.3结构型数组的定义和引用

—7.3.1结构型数组的定义和初始化structstudent/*定义结构型*/{longnumber;charname[10];charsex;floatscore[3];};structstudents[3]={{200001L,”Tom”,’m’,{78,86,92}},{200002L,”Lucy”,’f’,{85,69,82}},{200003L,”Jack”,’m’,{84,88,96}}};1.先定义结构型,再定义结构型数组并赋初值运算7.3结构型数组的定义和引用

—7.3.1结构型数组的定义和初始化这个定义语句将使用得数组s的各个元素的成员初值如表:7.3结构型数组的定义和引用

—7.3.1结构型数组的定义和初始化structstudent/*定义结构型*/{longnumber;charname[10];charsex;floatscore[3];}s[3]={{200001L,”Tom”,’m’,{78,86,92}},

{200002L,”Lucy”,’f’,{85,69,82}},

{200003L,”Jack”,’m’,{84,88,96}}};2.定义结构型的同时定义数组并赋初值7.3结构型数组的定义和引用

—7.3.1结构型数组的定义和初始化struct/*定义结构型*/{longnumber;charname[10];charsex;floatscore[3];}s[3]={{200001L,”Tom”,’m’,{78,86,92}},

{200002L,”Lucy”,’f’,{85,69,82}},

{200003L,”Jack”,’m’,{84,88,96}}};3.定义无名称的结构型的同时定义数组并赋初值7.3结构型数组的定义和引用1.结构型数组元素的引用格式如下;结构型数组名[下标].成员名2.结构型数组元素成员地址的引用格式如下:

&结构型数组名[下标].成员名7.2.2结构型数组元素成员的引用7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用结构型数组元素的引用格式如下:

结构型数组名[下标].成员名

【例7.5】输入3个学生的数据,每个学生的信息由学号、姓名和三门功课的成绩组成,然后计算每一个学生的总分,并输出总分最高的学生信息。

分析:将3个学生定义为结构型类型数组,学号为长整型、姓名为字符串、成绩为实型数组,总分、平均分为实型,为了保证输入记录不会出错,循环一次输入一条记录。7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用

/*源文件名:Li7_5.c*/

#include"stdio.h"

#defineN3

structstudent/*定义结构型*/

{

longnumber;

floatscore[7];/*score数组用来存放成绩*/

floattotal;

floataverage;

}stu[N];

main()

{

inti;

/*输入记录*/

for(i=0;i<N;i++)

{

scanf("%ld,%f,%f,%f,%f,%f,%f,%f",&stu[i].number,

&stu[i].score[0],&stu[i].score[1],&stu[i].score[2],

&stu[i].score[3],&stu[i].score[4],&stu[i].score[5],

&stu[i].score[6]);

stu[i].total=stu[i].score[0]+stu[i].score[1]+stu[i].

score[2]+stu[i].score[3]+stu[i].score[4]+

stu[i].score[5]+stu[i].score[6];7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用

stu[i].average=stu[i].total/7.0;

}

/*输出记录*/

for(i=0;i<N;i++)

printf("\n%ld,%f,%f\n",stu[i].number,stu[i].total,stu[i].average);}程序运行后,屏幕显示:7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用

从【例7.5】中可以看出,如果要输入多个学生的记录,只需要修改N的值,有兴趣的同学可以进一步研究如何实现排序。2.结构型数组元素成员地址的引用&结构型数组名[下标].成员名

【例7.6】结构型数组元素成员地址的引用

#include“string.h”

structstudent3

{

longnumber;

charname[10];

};7.3结构型数组的定义和引用

—7.3.2结构型数组元素成员的引用BACK

main()

{

structstudent3s[2];

long*p_number;

char*p_name;

p_number=&s[0].number;

p_name=s[1].name;

*p_number=2009080l;

strcpy(p_name,”Mary”);

printf(“%ld%s\n”,s[0].number,s[1].name);

}1)问题情景与实现

辅导员张老师在使用小王设计的学生成绩输入/输出小程序时,发现他还想要对输入后的学生成绩进行计算总分和平均分,故张老师找来小王同学,说明了需求,小王根据张老师的需求,参考了相关的资料,完善了原来的程序,帮助张老师解决了该问题。任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单

实现:

/* 功能:用结构体数组进行学生信息处理 */#include<string.h>#include<stdio.h>#defineN3structstudent{longnumber;charname[10];charsex;floatscore[3];floatave;}stu[N]={{1001L,"Lily",'f',{60,70,80}},{1002L,"Lucy",'f',{80,70,90}},{1003L,"Jim",'m',{80,70,75}}};任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单voidsort(structstudent*ptr,intm){

structstudentt; inti,j; for(i=1;i<m;i++) { for(j=0;j<m-i;j++) if((*(ptr+j)).ave<(*(ptr+j+1)).ave) { t=*(ptr+j); *(ptr+j)=*(ptr+j+1); *(ptr+j+1)=t; } }}voidmain(){structstudent*ptr;inti;ptr=stu;

for(i=0;i<N;i++){stu[i].ave=(stu[i].score[0]+stu[i].score[1]+stu[i].score[2])/3;}sort(ptr,N); /*按平均分从高到低排列*/printf("平均分最高的学生学号是:%ld\t姓名是:%s\n",stu[0].number,stu[0].name);printf("学号\t姓名\t性别\t语文\t数学\t英语\t平均分\n");任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单for(i=0;i<N;i++){

printf("%ld\t%s\t%c\t%f\t%f\t%f\t%f\n",stu[i].number,stu[i].name,stu[i].sex,stu[i].score[0],stu[i].score[1],stu[i].score[2],stu[i].ave);

}}任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单编译、连接、和运行程序。程序运行后,屏幕显示:2)相关知识

要完成上面的任务,小王必须要能熟练掌握结构型的定义方法,结构型变量、数组、指针变量的定义、初始化和结构体成员的引用方法;掌握简单链表的基本操作原理和应用,以及数组排序等相关知识点。任务2求平均分最高学生的学号、姓名输出排序后的学生成绩单7.4指向结构型数据的指针变量的定义和引用前面已经提到,结构型变量或数组元素的成员可以使用“成员运算符”来直接引用,也可以使用指向结构型数据成员的指针变量来引用,但不方便。我们还可以使用指向结构型变量或数组元素的指针变量来间接引用其成员。7.4指向结构型数据的指针变量的定义和引用■方式1(*指针变量).成员名■方式2指针变量->成员名■方式1比较好理解,其中“*指针变量”就代表了它所指向的结构型变量,利用“成员运算符”来引用,其作用相当于“结构型变量.成员名”。需要注意的是“*指针变量”必须用圆括号括住,因为“*”运算符的级别低于“.”运算符,如果不加括号,则优先处理“.”运算符,将出现“指针变量.成员名”,会造成语法错误。7.4.1指向结构型变量的指针(两种引用方式)7.4指向结构型数据的指针变量的定义和引用■方式2是一种新的引用方法,其中“->”称为“指向成员运算符”,也简称“指向运算符”。其运算级别和“()”、“[]”、“.”是同级的。指向运算符的左边必须是已指向某个结构型变量或数组元素的指针变量,其右边必须是对应结构型数据的成员名。7.4指向结构型数据的指针变量的定义和引用1.指针变量指向数组元素如果一个结构型数组元素的地址已赋予相同结构型指针变量(即指针变量指向结构型数组元素),可以使用下列两种方法来引用数组该元素的成员,其作用完全相同。方式1(*指针变量)。成员名方式2指针变量->成员名注意:这里的指针变量必须是指向某个数组元素的。例如,它指向的数组元素为“数组名[k]”,则上述两种引用方式均代表“数组名[k]。成员名”。7.4.2指向结构型数组的指针7.4指向结构型数据的指针变量的定义和引用2.指针变量指向数组首地址当一个结构型数组的首地址已经赋予相同结构型的指针变量(即指针变量指向结构型数组),可以使用下列两种方式来引用下标为i的数组元素成员,其作用完全相同。方式1(*(指针变量+i)).成员名方式2(指针变量+i)—>成员名注意:这里的指针变量必须是指向某个数组首地址的,则上述两种引用方式均代表“数组名[i].成员名”。7.4指向结构型数据的指针变量的定义和引用1.采用“全局外部变量方式传递数据”

2.采用“返回值方式传递数据”

3.采用“形式参数和实际参数结合的地址传递方式双向传递数据”7.4.3在函数间传递结构型数据7.5用指针处理链表我们知道用数组存放数据时,必须事先定义好数组的大小,不能在程序中随便进行调整。比如有的班有100人,有的班只有30人,如果要用同一个数组先后存放不同班级的学生数据,则必须定义长度为100的数组。如果事先难以确定一个班的最多人数,则必须把数组定义的足够大,以存放任何班级的学生数据,这显然非常浪费存储空间。为此C语言提供了动态数组的构建,即链表。7.5用指针处理链表链表如同一条铁链一样,一环扣一环,中间是不能断开的。这好比幼儿园的老师带领孩子出去玩,老师牵着第一个孩子的手,第一个孩子的另一只手牵着第二个孩子的手……这就是一个“链”,最后一个孩子有一只手空着,他就是“链尾”。要找这个队伍,就必须先找到老师,然后顺序找到每一个孩子。7.5.1什么是链表7.5用指针处理链表链表是一种动态数据结构,在程序的执行过程中可以根据需要随时间系统申请存储空间,动态地进行存储空间的分配。动态数据结构最显著的特点是包含的数据对象个数及其相互关系都可以按需要改变。常用的动态数据结构有链表、循环链表、双向链表三种。本章只介绍动态数据结构中最简单的单链表的建立及其基本操作。7.5用指针处理链表—7.5.1什么是链表1.单链表的结构链表有一个“头指针”head,它存放链表第一个结点的首地址,它没有数据,只是一个指针变量。从图8-2中我们看到它指向链表的第一个元素。链表的每一个元素称为一个“结点”(node)。每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号num、姓名name、性别sex、和成绩score等。另一个域为指针域,存放下一个结点的首地址,即指向下一个结点。链表中的每一个结点都是同一个结构类型。最后一个结点称为“链尾”,尾结点无后续点,因此不指向其他的元素,表尾结点的指针为空(NULL)。7.5用指针处理链表—7.5.1什么是链表图7-1单链表的结构7.5用指针处理链表—7.5.1什么是链表2.链表结点的构成

由于每个结点包含数据域或者指针域两部分内容,所以链表结点采用结构体表示。例如链表结点的数据结构定义如下:

structnode

{

intnum;

charname[10];

floatscore;

structnode*next;

};7.5用指针处理链表—7.5.1什么是链表

在链表结构中,除了数据项成员之外,还应包含一个指向本身的指针,该指针在使用时指向具有相同类型结构体的下一个结点。在链表结点的数据结构中,比较特殊的一点就是结构体内指针域的数据类型使用了未定义成功的数据类型。这是在C语言中唯一可以先使用后定义的数据结构。7.5用指针处理链表—7.5.1什么是链表3.如何建立和输出一个简单静态链表

【例7.10】建立一个如图7-2所示的简单链表,它由三个学生数据结点组成。请输出各结点中的数据。分析:为方便操作,将学生定义为一个结构体类型student,它有三个成员分别用来表示学生的学号、姓名和下一个结点的地址。在程序中逐个输入各学生的数据,通过地址赋值操作建立链表。利用当型循环用printf语句逐个输出个结点中成员的值。7.5用指针处理链表—7.5.1什么是链表图7-2简单链表7.5用指针处理链表—7.5.1什么是链表程序如下:

#include<studio.h>

structstudent

{

charno[6];

charname[10];

structstudent*next;

};

voidmain()

{

structstudent

A={“02001”,”tom”},B={“02002”,”jane”},C={“02003”,”henry”};

structsrudent*head=NULL,*p;7.5用指针处理链表—7.5.1什么是链表

head=&A;

A.next=&B;

B.next=&C;

C.next=NULL;

p=head;

while(p!=NULL){

printf(“No:%s\tName:%s\n”,p->no,p->name);

p=p->next;

}}程序运行后,屏幕显示:7.5用指针处理链表—7.5.1什么是链表4.动态存储分配函数■所谓“动态链表”就是链表的结构是动态分配和存储的,在程序的执行过程中要根据需要随时向系统申请存储空间,动态地进行存储空间的分配。在C语言中,提供了一下函数完成存储空间的动态分配和释放。■malloc函数■

calloc函数■

free函数7.5用指针处理链表—7.5.1什么是链表malloc函数■其函数原型为:void*malloc(unsignedsize)■其作用是在内存的动态存储区中分配一个长度为size的连续空间,并返回指向该空间起始地址的指针。若分配失败(如系统不能提供所需内存),则返回空指针NULL。7.5用指针处理链表—7.5.1什么是链表calloc函数■其函数原型为:void*calloc(unsignedn,unsignedsize)■该函数有两个形参n和size。其作用是在内存的动态存储区中分配n个长度为size的连续空间,并返回指向该空间首地址的指针。如用calloc(20,20)可以开辟20个(每个大小为20字节)的空间,即空间总长为400字节。若分配失败,则返回空指针NULL。7.5用指针处理链表—7.5.1什么是链表free函数■其函数原型为:void*free(void*ptr)■其作用是释放由malloc、calloc等函数申请的内存空间,使这部分内存区能够被其他变量所使用。ptr是最近一次调用malloc()或calloc()函数返回的值。Free函数没有返回值。■在使用上述函数时要注意,函数的原型在文件malloc.h和stdlib.h中定义。在程序中必须包含这两个头文件。下面的程序就是malloc()和free()两个函数配合使用的简单实例。7.5用指针处理链表—7.5.1什么是链表

【例7.11】存储空间的动态分配。

#include<stdlib.h>

#include<stdio.h>

#include<string.h>

main()

{

char*str;

if((str=(char*)malloc(10))==NULL)

{

printf(“Notenoughmemorytoallocatebuffer\n”);

exit(1);

}

strcpy(str,”welcome”);

printf(“Stringis%s\n”,str);

free(str);

}本例中首先用malloc函数向内存申请一块内存区,并把首地址赋予指针变量str,是str指向该区域。最后用free函数释放str指向的内存空间。整个程序包含了申请内存空间、使用内存空间、释放内存空间三个步骤,实现存储空间的动态分配。编译、连接、和运行程序。程序运行后,屏幕显示:7.5用指针处理链表—7.5.1什么是链表7.5用指针处理链表链表有五种基本操作:■建立■插入■删除■输出■查找7.5.2动态链表的基本操作7.5用指针处理链表—7.5.2动态链表的基本操作1.单链表的创建■建立动态链表就是建立结点空间、输入各结点数据和进行结点链接的过程,也就是在程序执行过程中从无到有地建立起一个链表。■通过以下实例来说明如何建立一个动态链表。

【例7.12】建立一个链表存放学生数据。为简单起见,我们假定学生数据结构中有学号和年龄两项。编写一个建立链表的函数creat。7.5用指针处理链表—7.5.2动态链表的基本操作创建单链表的算法7.5用指针处理链表—7.5.2动态链表的基本操作分析:整个链表的创建过程可用下图来表示。第一步,创建空表:head→NULL第二步,申请新结点:第三步,若是空表,将新结点接到表头:若是非空表:第四步,

第五步,申请新结点:若数值为负,则结束,否则转到第三步。7.5用指针处理链表—7.5.2动态链表的基本操作7.5用指针处理链表—7.5.2动态链表的基本操作创建单链表实例程序清单

#defineLENsizeof(structstu)

sructstu/*结构stu定义为外部类型,方便程序中的各个函数使用*/

{

intnum;

intage;

structstu*next;

};

structstu*creat(void)

/*creat函数用语动态建立一个有n个结点的链表,返回与结点相同类型的指针*/

{

structstu*p1,*p2,*head;

/*head为头指针,p2指向已建链表的最后一个结点,

p1始终指向当前新开辟的结点*/

intn=0;7.5用指针处理链表—7.5.2动态链表的基本操作

p1=p2=(structstu*)malloc(LEN);

/*申请新结点,长度与stu长度相等;同时使指针变量p1、p2指向新结点*/

scanf(“%d%d”,&p1->num,&p1->page);/*输入结点的值*/

head=NULL;

while(p1->num!=0)/*输入结点的数值不为0*/

{

n++;

if(n==1)head=p1;/*输入的结点为第一个新结点即空表,将输入的结点数据接入表头*/

elsep2->next=p1;/*非空表即输入的结点不是第一个结点,将输入的结点数据接到表尾*/

p2=p1;

p1=(structstu*)malloc(LEN);/*申请下一个新结点*/

scanf(“%d%d”,&p1->num,&p1->page);

}7.5用指针处理链表—7.5.2动态链表的基本操作建立链表的具体步骤(1)定义链表的数据结构。(2)创建一个空表。(3)利用malloc()函数向系统申请分配一个结点。(4)若是空表,则将新结点接到表头;若是非空表,则将新结点接到表尾。(5)判断一下是否有后续结点要接入链表,若有则转到步骤(3),否则结束。

p2->next=NULL;

return(head);/*返回链表的头指针*/}7.5用指针处理链表—7.5.2动态链表的基本操作2.单链表的插入■链表的插入是指将一个结点插入到一个已有的链表中。■【例7.13】以前面建立的动态链表为例,编写一个函数,使其能够在链表中指定的位置插入一个结点。单链表插入实例分析要在一个链表的指定位置插入结点,要求链表本身必须已按某种规律进行了排序。例如学生数据链表中,各结点的成员项按学号由小到大顺序排列。如果要求按学号顺序插入一个结点,则要将插入的结点依次与链表中各结点比较,寻7.5用指针处理链表—7.5.2动态链表的基本操作找插入位置。结点可以插在表头、表中、表尾。结点插入存在以下几种情况。

1.如果原表是空表,只需使链表的头指针head指向被插结点。

2.如果被插结点值最小,则应插入第一个结点之前。将头指针head指向被插结点,被插结点的指针域指向原来的第一个结点。7.5用指针处理链表—7.5.2动态链表的基本操作

3.如果在链表中某位置插入,使插入位置的前一结点的指针域指向被插结点,使被插结点的指针域指向插入位置的后一个结点。

4.如果被插结点值最大,则在表尾插入,使原表尾结点指针域指向被插结点,被插结点指针域置为NULL。7.5用指针处理链表—7.5.2动态链表的基本操作单链表插入实例图形分析7.5用指针处理链表—7.5.2动态链表的基本操作单链表插入实例操作步骤在表头插入结点p1,head=p1在表中插入结点p1,p3->next=p1;p1->next=p2;在表尾插入结点p1,p2->next=p1;p1->next=NULL链表插入操作7.5用指针处理链表—7.5.2动态链表的基本操作单链表插入实例程序清单structstu*insert(structstu*head,structstu*p1){

structstu*p2,*p3;

p2=head;

if(head=NULL)/*空表插入*/

{

head=p1;

head=p1;

p1->next=NULL;7.5用指针处理链表—7.5.2动态链表的基本操作

}

else

{

while((p1->num>p2->num)&&(p2->next!=NULL))

{

p3=p2;

p2=p2->next;/*找插入位置*/

}

if(p1->num<=p2->num)

{if(head==p2)head=p1;/*在第一结点之前插入*/

elsep3->next=p1;/*在其他位置插入*/

p1->next=p2;}

else

{p2->next=p1;

p1->next=NULL;}/*在表末插入*/

}7.5用指针处理链表—7.5.2动态链表的基本操作链表插入操作的具体步骤1.定义一个指针变量p1指向被插结点。2.首先判断链表是否为空,为空则使head指向被插结点。3.链表若不是空,用当型循环查找插入位置。4.找到插入位置后判断是否在第一个结点之前插入,若是则使head指向被插入结点,被插结点指针域指向原第一结点;否则在其他位置插入;若插入的结点大于表中所有结点,则在表末插入。5.函数返回值为链表的头指针。

returnhead;/*返回链表的头指针*/}7.5用指针处理链表—7.5.2动态链表的基本操作3.单链表的删除

■链表中不再使用的数据,可以将其从表中删除并释放其所占用的空间,但注意在删除结点的过程中不能破坏链表的结构。■【例7.14】以前面建立的动态链表为例,编写一个删除链表中指定结点的函数delete1。单链表的删除实例分析假设链表按学生的学号排列,当某结点的学号与指定值相同时,将该结点从链表中删除。首先从头到尾依次查找链表中给结点,并与各结点的学生学号做比较,若相同,则查找成功,否则,找不到结点。由于结点在链表中可以有三种不同位置:7.5用指针处理链表—7.5.2动态链表的基本操作位于开头,中间或结尾,因此从链表中删除一个结点主要分两种情况,即删除链表头结点和非表头结点。

1.如果被删除的结点是表头结点,使head指向第二个结点。

2.如果被删除的结点不是表头结点,使被删结点的前一结点指向被删结点的后一结点。7.5用指针处理链表—7.5.2动态链表的基本操作单链表的删除实例图形分析7.5用指针处理链表—7.5.2动态链表的基本操作单链表的删除实例操作步骤图7-8链表删除操作7.5用指针处理链表—7.5.2动态链表的基本操作单链表的删除实例程序清单structstu*delete(structstu*head,intnum)

/*以head为头指针删除num所在结点*/

{

structstu*p1,*p2;

if(head=NULL)/*如为空表,输出提示信息*/

{

printf(“\nemptylist!\n”);

gotoend;

}

p1=head;

while(p1->num!=num&&p1->next!=NULL)

/*当不是要删除的结点,而且也不是最后一个结点时,继续循环*/

{

p2=p1;p1=p1->next;

}/*p2指向当前结点,p1指向下一结点*/7.5用指针处理链表—7.5.2动态链表的基本操作

if(p1->num==num)

{

if(p1==head)head=p1->next;

/*如找到被删结点,且为第一结点,则使head指向第二结点,否则使p2所指结点的指针指向下一结点*/

else

p2->next=p1->next;

free(p1);

printf(“Thenodeisdeleted\n”);

}

else

printf(“Thenodenotbeenfound!\n”);

end:

return(head);}7.5用指针处理链表—7.5.2动态链表的基本操作■定义一个指针变量p指向链表的头结点。■用循环从头到尾依次查找链表中各结点并与各结点的学生学号做比较,若相同,则查找成功退出循环。■判断该结点是否为表头结点,如果是使head指向第二个结点,如果不是使被删结点的前一结点指向被删结点的后一结点。同时结点个数减1。链表删除操作的具体步骤7.5用指针处理链表—7.5.2动态链表的基本操作4.单链表的输出■链表的输出比较简单,只要将链表中的各个结点数据依次输出即可■【例7.15】编写一个输出链表的函数print。7.5用指针处理链表—7.5.2动态链表的基本操作设立一个指针变量p,先指向链表的头结点,输出该结点的数据域,然后使指针p指向下一个结点,重复上述工作,直到链表尾部。具体算法如图所示。

输出单链表的算法7.5用指针处理链表—7.5.2动态链表的基本操作

单链表的输出实例程序清单#defineLENsizeof(structstu)

structstu

{

intnum;

intage;

structstu*next;

};

voidprint(structstu*head)

/*print函数用于输出以head为头的链表各结点的值*/

{

structstu*p;

p=head;/*取得链表的头指针*/

while(p!=NULL)

{

printf(“%6d%6d”,p->num,p->page);/*输出链表结点的值*/

p=p->next;/*使指针变量p指向下一个结点,跟踪链表增长*/

}}7.5用指针处理链表—7.5.2动态链表的基本操作7.5用指针处理链表—7.5.2动态链表的基本操作

【例7.16】在前面学习的建立链表,输出链表,删除结点,插入结点操作的基础上,试编一主函数将以上的建立链表,输出链表,删除结点,插入结点的函数组织在一起,并输出全部结点的值。链表综合实例7.5用指针处理链表—7.5.2动态链表的基本操作

/*源文件名:Li7_16.c*/

#defineNULL0

main()

{

structstu*head;

structstu*stu;

intdel_num;

printf(“inputrecords:\n”);

head=creat();/*建立链表,并返回表头*/

print(head);/*输出链表*/

printf(“\nInputthedeletednumber:”);

scanf(“%d”,&del_num);while(del_num!=0)

{

head=delete1(head,del_num);/*从链表中删除del_num结点*/

print(head);/*输出链表*/7.5用指针处理链表—7.5.2动态链表的基本操作

printf(“\nInputthedeletednumber:”);

scanf(“%d”,&del_num);

}

printf(“\nInputtheinsertedrecord:”);

stu=(structstu*)malloc(LEN);

scanf(“%d,%d”,&stu->num,&stu->age);while(stu->num!=0)

{

head=insert(head,stu);/*在链表中插入一节结点stu*/

print(head);/*输出链表*/

printf(“\nInputtheinsertedrecord:”);

stu=(structstudent*)malloc(LEN);

scanf(“%d,%d”,&stu->num,&stu->age);

}

free(stu)/*对于num=0的结点,未插入,应删除其空间*/}7.6共用型共用型和结构型的比较

图7-10结构型和共用型的比较7.6共用型union共用型名

{

数据类型1成员名1;

数据类型2成员名2;

数据类型n成员名n;

};注意在右花括号的后面有一个语句结束符分号。7.6.1共用型的定义7.6共用型

—7.6.1共用型的定义共用型的定义实例例如:为了节省内存,可以将不同的三个数组定义在一个共用型中,

总计可节省300个单元:

unionc_i_f

{

charc1[100];/*该成员占用100个单元*/

inti2[100];/*该成员占用200个单元*/

floatf3[100];/*该成员占用400个单元*/

};/*该共用型数据共用400个单元*/■需要提醒读者注意的是,共用型数据中每个成员所占用的内存单元都是连续的,而且都是从分配的连续内存单元中第一个内存单元开始存放的。所以,对共用型数据来说,所有成员的首地址都是相同的。这是共用型数据的一个特点。7.6共用型

—7.6.1共用型的定义7.6共用型当定义了某个共用型后,就可以使用它来定义相应共用类型的变量、数组、指针等。共用型变量、数组的定义和结构型变量、数组的定义方法相同,也有三种:1.先定义共用型,然后定义变量、数组;2.定义共用型的同时定义变量、数组;3.定义无名称的共用型同时定义变量、数组。7.6.2共用型变量的定义7.6共用型

—7.6.2共用型变量的定义1.先定义共用型,然后定义变量u1与数组u2[5]。unionu{inti_a[10];/*该成员占用20个单元*/charc_a[3][4];/*该成员占用12个单元*/longl;/*该成员占用4个单元*/doubled;/*该成员占用8个单元*/};/*该共用型数据共占用20个单元*/unionuu1,u2[5];7.6共用型

—7.6.2共用型变量的定义2.定义共用型的同时定义变量u1与数组u2[5]。unionu{inti_a[10];/*该成员占用20个单元*/charc_a[3][4];/*该成员占用12个单元*/longl;/*该成员占用4个单元*/doubled;/*该成员占用8个单元*/}u1,u2[5];7.6共用型

—7.6.2共用型变量的定义3.定义无名称的共用型同时定义变量u1与数组u2[5]。union/*无名称*/{inti_a[10];/*该成员占用20个单元*/charc_a[3][4];/*该成员占用12个单元*/longl; /*该成员占用4个单元*/doubled;/*该成员占用8个单元*/}u1,u2[5];7.6共用型■共用型变量或数组元素成员的引用格式如下:

共用型变量名.成员名■共用型变量成员地址的引用和指针变量的使用格式如下:

指针变量=&共用型变量名.成员名■共用型变量地址的引用和指针变量的使用格式如下:指针变量=&共用型变量名7.6.3共用型变量的引用7.7枚举型顾名思义,就是把有限的数据一一例举出来,例如:■一个星期7天■性别只有”男”和”女”■中国有23个省,5个自治区,4个直辖市,2个特别行政区等。■如下图:在填写用户资料中的所在城市时,把中国的23个省,5个自治区,4个直辖市,2个特别行政区都列举出来,供注册者选择,这样有利于数据的规范且不会出错。枚举型和结构型、共用型一样,也是一种用户自定义的数据类型,在使用时必须先定义后使用。7.7枚举型7.7枚举型■

enum枚举型名■

{枚举常量1,枚举常量2,…枚举常量n};■注意在右花括号的后面有一个语句结束符分号。■其中:枚举型名是用户取的标识符;■枚举常量是用户给常量取的标识符。■该语句定义了一个名为“枚举型名”的枚举类型,该枚举型中含有n个枚举常量,每个枚举型常量均有值。C语言规定枚举常量的值依次等于0、1、2、…、n-1.7.7.1枚举型的定义7.7枚举型—7.7.1枚举型的定义枚举型定义实例例如:定义一个表示星期的枚举型:

enumweek

{sun,mon,tue,wed,thu,fri,sat};

定义的这个枚举型共有7个枚举常量,它们的值依次为0、1、2、3、4、

温馨提示

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

最新文档

评论

0/150

提交评论