结构体和共用体C语言程序设计谭浩强解_第1页
结构体和共用体C语言程序设计谭浩强解_第2页
结构体和共用体C语言程序设计谭浩强解_第3页
结构体和共用体C语言程序设计谭浩强解_第4页
结构体和共用体C语言程序设计谭浩强解_第5页
已阅读5页,还剩81页未读 继续免费阅读

下载本文档

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

文档简介

会计学1结构体和共用体C语言程序设计谭浩强解11.1-11.4结构体类型和结构体变量

结构体——是用户根据自己的需要一种构造类型数据。

结构体由若干不同类型的数据项组成,构成结构体的各个数据项称为结构体成员。

struct[结构体名]{

数据类型1成员名1;

数据类型2成员名2;……

数据类型n成员名n;};{}中是组成该结构体的成员。成员类型可以是基本型或构造型struct是关键字,不能省略用户定义的合法标识符。可省:无名结构体末尾分号不能省

结构体类型声明----------构造自己所需的结构体类型1、结构体类型声明第1页/共86页namenumsexagescoreaddr2字节2字节20字节1字节4字节30字节……..struct

student{intnum;charname[20];charsex;intage;floatscore;charaddr[30];};

结构体名成员名例声明结构体类型structstudent注意:结构体类型声明只是定义了一种新的类型,类似int等类型。它是对结构的组织形式的描述,(类似于房屋户型图),系统还没分配实际内存空间。结构的组织形式描述只有定义结构体类型的变量,系统才分配内存空间第2页/共86页一般形式:struct结构体名{

类型标识符成员名;类型标识符成员名;

…………….};struct结构体名变量名表列;(1)先定义(声明)结构体类型再定义变量名例structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];};//结构体类型的声明

structstudentstudent1,student2;//结构体变量的定义2、结构体变量定义有了类型后,就可以定义变量。三种形式:第3页/共86页(2)定义结构体类型的同时定义结构体变量一般形式:struct结构体名{

类型标识符成员名;类型标识符成员名;

…………….}变量名表列;例structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];}student1,student2;第4页/共86页(3)直接定义结构体变量(即不出现结构体名)一般形式:struct{

类型标识符成员名;类型标识符成员名;

…………….}变量名表列;例struct{intnum;charname[20];charsex;intage;floatscore;charaddr[30];}student1,student2;用无名结构体直接定义变量只能一次第5页/共86页3、结构体变量需要的内存

等于结构体变量所有成员占内存之和22012 430Numnamesexagescoreaddrstudent1student1在内存中占59个字节,(2+20+1+2+4+30=59)。利用表达式sizeof(student1)或sizeof(structstudent)或可自动求得注意:结构体类型与结构体变量概念不同类型:不分配内存;变量:分配内存类型:不能赋值、存取、运算;变量:可以第6页/共86页4、结构体变量初始化

就是为成员赋初值。根据前面结构体变量定义形式的三种情况,初始化的形式也有三种。struct结构体名{

类型标识符成员名;类型标识符成员名;

…………….};struct结构体名结构体变量={初始数据};例structstudent{intnum;charname[20];charsex;intage;charaddr[30];};structstudentstudent1={100102,“WangLin”,‘M’,20,“Beijing”};形式一:第7页/共86页Student1(初始化后)100102WangLiM2098Beijing22012 430NumnamesexagescoreaddrStudent1(初始化前)此时,才真正货真价实。定义类型不分配空间。定义变量时分配空间,但值不确定,初始化后值确定。第8页/共86页形式二:struct结构体名{

类型标识符成员名;类型标识符成员名;

…………….}结构体变量={初始数据};例structstudent{intnum;charname[20];charsex;intage;charaddr[30];}stu1={112,“WangLin”,‘M’,19,“200BeijingRoad”};

5、结构体变量初始化第9页/共86页形式三:例struct{intnum;charname[20];charsex;intage;charaddr[30];}stu1={112,“WangLin”,‘M’,19,“200BeijingRoad”};

struct{

类型标识符成员名;类型标识符成员名;

…………….}结构体变量={初始数据};5、结构体变量初始化第10页/共86页6、结构体变量使用(1)引用规则:一般情况下结构体变量不能整体引用,只能引用变量成员引用方式:结构体变量名.成员名例structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];}stu1,stu2;stu1.num=10;stu1.score=85.5;stu1.score+=stu2.score;stu1.age++;.

成员(分量)运算符优先级:1最高级结合性:从左向右结构体中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。成员名可以与程序中的变量名相同,二者不代表同一对象。第11页/共86页例:不能将一个结构体变量作为一个整体进行输入和输出。只能对各个成员变量分别输入输出。structstudent{intnum;charname[20];charsex;intage;charaddr[30];}stu1={112,“WangLin”,‘M’,19,“200BeijingRoad”};printf(“%d,%s,%c,%d,%f,%s\n”,stu1);()printf(“%d,%s,%c,%d,%f,%s\n”,stu1.num,,stu1.sex,stu1.age,stu1.addr);(√)scanf(″%d,%s,%c,%d,%f,%s″,&student1);()scanf(″%d″,&student1.num);(√)第12页/共86页(2)例外:允许将一个结构体变量直接赋值给另一个具有相同结构的结构体变量例如:structstudent{charnum[15];charname[20];intscore[4];ints;}student1={"2007101010","wang",{89,90,87,80},0};main(){structstudentstudent2;

student2=student1;…….}第13页/共86页例structdate{intmonth;intday;intyear;};structstudent{intnum;charname[20];structdatebirthday;}student1;numnamebirthdaymonthdayyear结构体成员本身又是一个结构体类型。例:声明structstudent类型时,将成员birthday指定为structdate类型7、结构体类型的嵌套结构体嵌套时逐级引用(只能对最低级的成员进行赋值或存取以及运算)student1.birthday.month=3(√)student1.birthday=3()第14页/共86页11.5、结构体数组1、定义结构体数组:每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项。也有三种方法:1、定义结构体后定义structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];};structstudentstu[3];2、定义结构体时同时定义structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];}stu[3];第15页/共86页一般初始化省略维数[]定义后初始化一般初始化structstudent{intnum;charname[20];charsex;intage;floatscore;}stu[3]={{10101,"李宁",'M',18,87.5},{10102,"张凡",'M',19,99},{10103,"王敏",'F',20,78.5}};定义后初始化structstudent{intnum;charname[20];charsex;intage;floatscore;};structstudentstu[3]={{10101,"李宁",'M',18,87.5},{10102,"张凡",'M',19,99},{10103,"王敏",'F',20,78.5}};

每个数组元素的初始数据都用花括号括起来。2、结构体数组的初始化结构数组[n]={{初值表1},{初值表2},...,{初值表n}};第16页/共86页图11-4图11-5第17页/共86页结构体数组元素类似于一个结构体变量只能对结构体数组元素的成员进行输入、输出或其它基本操作例如:

structs_type{charnum[15];charname[20];intscore[4];ints;}stu[3]={{"2007101010","wang",{89,90,87,80},0},{"2007101011","Li",{88,95,77,70},0},

{"2007101012",Jiang",{79,65,69,76},0}};main(){inti;for(i=0;i<3;i++)for(j=0;j<4;j++)stu[i].s+=stu[i].score[j];….}3、结构体数组元素的使用第18页/共86页例11.2统计侯选人选票。有三个候选人,每次输入一个得票的候选人名,要求最后输出个人得票结果。structperson{charname[20];intcount;}leader[3]={“Li”,0,“Zhang”,0,”Wang“,0};//全局结构体数组main(){inti,j;charleader_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);}namecountLiZhangWang000运行结果:Li↙Fun↙Zhang↙Zhang↙Fun↙Li↙Fun↙Zhang↙Li↙Li:4Zhang:3Fun:3第19页/共86页

程序定义一个全局的结构体数组leader,它有3个元素,每一个元素包含两个成员name(姓名)和count(票数)。在定义数组时使之初始化,使3位候选人的票数都先置零。

在主函数中定义字符数组leader-name,它代表被选人的姓名,在10次循环中每次先输入一个被选人的具体人名,然后把它与3个候选人姓名相比,看它和哪一个候选人的名字相同。在输入和统计结束之后,将3人的名字和得票数输出。

namecountLiZhangWang000第20页/共86页11.6用指针访问结构体1、指向结构体变量的指针

可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。成员运算符.指向运算符->优先级:1级,最高结合方向:从左向右(*)与->等价定义形式:

struct结构体名

*结构体指针名;

例:structstudent*p;使用形式:

使用结构体指针变量引用成员形式

(*结构体指针名).成员名结构体指针名->成员名结构体变量名.成员名(*结构体指针名).成员名结构体指针名->成员名结构体变量名.成员名第21页/共86页示例11.3main(){structstudent{longintnum;charname[20];charsex;floatscore;}stu,*p;//定义结构体变量stu和结构体指针变量pp=&stu;//p指向结构体stustu.num=89101;//对第1个成员赋值

strcpy(,“LiLin”);//对第2个成员赋值

p->sex=‘M’;//利用指针对第3个成员赋值

p->score=89.5;printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n",

(*p).num,p->name,stu.sex,p->score);}运行结果:No:89101

name:LiLinsex:Mscore:89.500000

第22页/共86页2指向结构体数组的指针structstudent{intnum;charname[20];charsex;intage;}stu[3]={{10101,"LiLin",'M',18},{10102,"ZhangFun",'M',19}, {10104,"WangMin",'F',20}};main(){structstudent*p;for(p=stu;p<stu+3;p++)

printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age);}numnamesexagestu[0]pstu[1]stu[2]p+1指针变量也可以用来指向结构体数组中的元素。注意:p++指针移动1次,跨过一个structstudent结构体类型大小第23页/共86页程序分析:p是指向structstudent结构体类型数据的指针变量。在for语句中先使p的初值为stu,也就是数组stu第一个元素的起始地址。在第一次循环中输出stu[0]的各个成员值。然后执行p++,使p自加1。p加1意味着p所增加的值为结构体数组stu的一个元素所占的字节数。执行p++后p的值等于stu+1,p指向stu[1]。在第二次循环中输出stu[1]的各成员值。在执行p++后,p的值等于stu+2,再输出stu[2]的各成员值。在执行p++后,p的值变为stu+3,已不再小于stu+3了,不再执行循环。图11-8第24页/共86页请分析以下几种运算:p->num得到p指向的结构体变量中的成员num的值。p->num++得到p指向的结构体变量中的成员num的值,用完该值后使它加1。++p->num得到p指向的结构体变量中的成员num的值加1,然后再使用它。(++p)->num先使p自加1,然后得到它指向的元素中的num成员值(即10102)。(p++)->num先得到p->num的值(即10101),然后使p自加1,指向stu[1]。成员运算符.指向运算符->优先级:最高结合方向:从左向右(*)与->等价总结:结构体成员变量引用方式①结构体变量.成员名②(*p).成员名③p->成员名其中,->称为指向运算符第25页/共86页3用结构体变量和指向结构体的指针作函数参数

将一个结构体变量的值传递给另一个函数,有3个方法:用结构体变量的成员作参数。(2)用结构体变量作实参。(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。值传递值传递,不推荐使用地址传递第26页/共86页例11.5结构体变量作为函数参数

有一个结构体变量stu,内含学生学号、姓名和3门课程的成绩。要求在main函数中赋予值,在另一函数print中将它们输出。今用结构体变量作函数参数。#include<stdio.h>#include<string.h>#defineFORMAT“%d\n%s\n%f\n%f\n”

structstudent

{

intnum;

charname[20];

floatscore[3];

};第27页/共86页voidmain()

{voidprint(structstudent);

structstudentstu;

stu.num=12345;strcpy(,″LiLin″);stu.score[0]=67.5;stu.score[1]=89;stu.score[2]=78.6;

print(stu);

}

voidprint(structstudentstu)

{printf(FORMAT,stu.num,,stu.score[0],stu.score[1],stu.score[2]);}运行结果:12345LiLi67.50000089.00000078.599998第28页/共86页例11.6将上题改用指向结构体变量的指针作实参。

#include<stdio.h>

structstudent

{intnum;

charname[20];

floatscore[3];

};stu={12345,″LiLi″,67.5,89,78.6};voidmain()

{voidprint(structstudent*);/*形参为指向结构体的指针变量*/

print(&stu);/*实参改为stu的起始地址*/}

voidprint(structstudent*p)/*形参类型修改了*/

{printf(FORMAT,p->num,p->name,p->score[0],p->score[1],p->score[2]);/*用指针变量调用各成员的值*/

}运行结果:12345LiLi67.50000089.00000078.599998第29页/共86页说明:例11.5值传递时(1)在发生函数调用时,形参结构体变量也要占用内存空间,接收实参结构体变量传递来的信息,因此函数之间传递结构体变量会带来时间和空间的巨大开销;(2)形参与实参之间是“值传递”的方式,被调函数对形参结构体变量的修改并不能传递给实参,即主调函数无法得到处理后的数据;(3)所以虽然语法上允许,但一般很少采用这种传递方式。而是采用例11.6传递结构体地址的方法,使得在调用函数与调用函数之间共享结构体变量数据。第30页/共86页链表是一种最常见的数据结构,它动态地进行存储分配。结构体数组:必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)链表有单向链表、双向链表、环形链表等形式。11.7用指针处理链表第31页/共86页图11-10链表是将若干个数据项按一定的原则连接起来的表。

链表组成:(1)头指针变量head──存放首元素地址,指向链表的首结点。(2)每个结点由两个域组成:

数据域──存储结点本身的信息。(用户有用信息)

指针域──存放下一个结点的地址。(3)尾结点的指针域置为“NULL”,作为链表结束的标志。连接原则:(1)前一个结点指向下一个结点;

(2)只有通过前一个结点才能找到下一个结点。11.7.1链表概述第32页/共86页链表结点数据可以用结构体来描述,例如structstudent

{

longnum;

floatscore;

structstudent*next;/*指向下一结点*/

};其中成员num和score用来存放结点中的有用数据(用户需要用到的数据),next是指针类型的成员,它指向structstudent类型数据(这就是next所在的结构体类型)第33页/共86页voidmain(){ structstudenta,b,c,*head,*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;//输出链表的数据信息

do { printf("%ld%5.1f\n",p->num,p->score); p=p->next; }while(p!=NULL);}静态链表:所有结点在程序中定义,没有动态申请空间,用完后也不能够释放空间11.7.2简单链表运行结果:8910189.58910390.08910785.011.7.2简单链表第34页/共86页程序分析:

开始时使head指向a结点,a.next指向b结点,b.next指向c结点,这就构成链表关系。“c.next=NULL”的作用是使c.next不指向任何有用的存储单元。在输出链表时要借助p,先使p指向a结点,然后输出a结点中的数据,“p=p->next”是为输出下一个结点作准备。p->next的值是b结点的地址,因此执行“p=p->next”后p就指向b结点,所以在下一次循环时输出的是b结点中的数据。第35页/共86页11.7.3处理动态链表所需的函数malloc函数

函数原型:

void*malloc(unsignedintsize)

功能:

在内存的动态存储区分配size个字节的连续存储空间。返回值:成功,返回一个指针,该指针指向存储空间首地址,基类型为void;失败,返回空指针(NULL)。原因:内存空间不够。由于返回值是空类型指针,所以在调用时必须进行强制类型转换,将其转换成所需的类型。

如:int*p=NULL;p=(int*)malloc(sizeof(int));库函数<stdlib.h>和<alloc.h>提供动态地开辟和释放存储单元的有关函数:第36页/共86页(2)calloc函数函数原型:void*calloc(unsignedn,unsignedsize)功能:

在内存的动态存储区分配n个长度为size的连续空间。返回值:成功,返回所分配内存的首地址,基类型为void;失败,则返回空指针NULL。如:int*p=NULL;p=(int*)calloc(10,sizeof(int));

用calloc函数可以为一维数组开辟动态存储空间,为数组元素个数,每个元素长度为Size。第37页/共86页(3)free函数

函数原型:

voidfree(void*p)

功能:

释放由p指向的空间。该地址p必须是最近一次由

malloc、calloc、realloc函数申请成功返回的指针。

free函数无返回值使用free前应检查该指针是否为空。如:int*p=NULL;p=(int*)malloc(10*sizeof(int));if(p!=NULL){free(p);p=NULL;}

注意:free和NULL配对使用!第38页/共86页(4)realloc函数

void*realloc(void*ptr,size_tsize)

功能:

释放ptr指向的空间,并按size指定的大小重新分配空间,同时将原有数据拷贝到新分配的内存区域。

返回值:成功,返回所分配内存的首地址;失败,则返回NULL。

如:int*p=NULL;p=malloc(10*sizeof(int));……p=realloc(p,40*sizeof(int));第39页/共86页对链表的基本操作(1)创建(create)链表:从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。(2)检索(scan)操作:按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点,则称为检索成功;否则,称为检索失败。(3)插入(insert)操作:在结点ki-1与ki之间插入一个新的结点k’,使线性表的长度增1。(4)删除(delete)操作:删除结点ki,使线性表的长度减1。第40页/共86页例11.8写一个函数creat(),建立一个有3个学生的单向动态链表。分析建立过程:设:链表结构为:structstudent

{

long

num;

floatscore;

structstudent*next;

};约定:当输入的num等于零时,表示建立过程结束。定义以下变量:两个指针*p1

,*p2

structstudent*head;/*表头*/

structstudent*p1;

/*新建结点*/

structstudent*p2;

/*表尾结点*/11.7.4建立动态链表(1)创建(create)链表:从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。第41页/共86页如何开辟第1个节点?开始时:head=NULL;(1)先用malloc函数开辟第1个节点,并使p1、p2指向它。(2)如果输入的p1->num≠

0,则输入的是一个有效的节点,而且是第1个结点数据(n=1),令head=p1,使head也指向新开辟的结点。(3)这样,p1所指向的新开辟的结点就成为链表中第1个结点,同时,p2=p1。p2=p1=(structstudent*)malloc(LEN);scanf("%ld,%f",&p1->num,&p1->score);第1个结点head=p1第42页/共86页如何开辟第2个节点:(1)再开辟一个新结点并使p1指向它,接着输入该结点的数据。p1=(structstudent*)malloc(LEN);scanf("%ld,%f",&p1->num,&p1->score);第43页/共86页(2)如果输入的p1->num≠0,则应链入第2个结点(n=2)。将p1指向的新结点的地址赋给第1个结点的next成员。(3)接着使p2=p1,也就是使p2也指向刚建立的新结点。p2重新指向表尾结点。非第一个结点p2->next=p1;p2=p1;如何开辟第2个节点(续):第44页/共86页如何开辟第3个节点:(1)再新开辟一个结点并使p1指向它,接着输入该结点的数据。(2)如果输入的p1->num≠0,则应链入第3个结点(n=3)。将p1指向的新结点的地址赋给第2个结点的next成员。

p2->next=p1;(3)接着使

p2=p1;

也就是使p2也指向刚建立的新结点。

p2重新指向表尾结点。p2=p1;非第一个结点p2->next=p1;第45页/共86页(1)再开辟一个新结点并使p1指向它,接着输入该结点的数据。(2)由于p1->num的值为0,此新结点不应被连接到链表中.p2->next=NULL

建立链表过程至此结束,p1最后所指的结点未链入链表中,第3个结点的next成员的值为NULL,它不指向任何结点。如何封尾巴:p2->next=NULLNULL第46页/共86页第47页/共86页建立链表的函数如下:

#include<stdio.h>#include<malloc.h>#defineNULL0//令NULL代表0,用它表示“空地址#defineLENsizeof(structstudent)//令LEN代表struct//student类型数据的长度

structstudent{longnum;floatscore;structstudent*next;};intn;//structstudent、n为全局变量,本文件模块中各函数均可使用它第48页/共86页structstudent*creat()//创建链表,返回表头指针{

structstudent*head;//表头

structstudent*p1;

//新建结点*/

structstudent*p2;

//表尾结点*/

n=0;//结点数为0*/

head=NULL;//还没有任何结点,表头为指向空*/

p1=(structstudent*)malloc(LEN);//创建一个新结点p1

p2=p1;//表尾p2也指向p1*/

scanf("%ld,%f",&p1->num,&p1->score);//读入第一个结点的学生数据*/第49页/共86页while(p1->num!=0)//假设num=0表示输入结束

{

n=n+1;

if(n==1)head=p1;

//第一个新建结点是表头

else

p2->next=p1;//原表尾的下一个结点是新建结点

p2=p1;//新建结点成为表尾

p1=(structstudent*)malloc(LEN);//新建一个结点

scanf(“%ld,%f”,&p1->num,&p1->score);//读入新建结点的学生数据

}free(p1);

//对于num=0的结点,未加入链表,应删除其空间

p2->next=NULL;//输入结束,表尾结点的下一个结点为空

return(head);

//返回表头指针

}第50页/共86页实际上书上程序还有不完美的情况:p1=(structstudent*)malloc(LEN);scanf(“%ld,%f”,&p1->num,&p1->score);

改成:p1=(structstudent*)malloc(LEN);

if(p==NULL)//或if(!p1){printf("内存分配出错");exit(1);}scanf(“%ld,%f”,&p1->num,&p1->score);p1->next=NULL;第51页/共86页11.7.5输出链表

只要已知表头结点head,设一个指针变量p,先指向第1个结点p=head,输出当前p所指的结点,通过p=p->next可以找到下一个结点,从而可以输出链表的全部结点数据。voidprint(structstudent

*head)

{

structstudent*p;

//指向要输入的结点

printf("\nNow,These%drecordsare:\n",n);

p=head;

if(p==NULL)return;//不是空表

do{

printf(“%ld%5.1f\n”,p->num,p->score);

p=p->next;//指向下个结点

}while(p!=NULL);

}第52页/共86页第53页/共86页11.7.6对链表的删除操作

从链表中删除一个结点,分两步:(1)找到要删除的节点(2)删除节点,把它从链表中分离出来,撤销原有的链接关系即可。算法:设两个指针变量p1、p2,(1)开始p1=head,用p1=p1->next一直找到需要删除的结点,设关键字num,num=p1->num代表找到。(2)让p1不断移动寻找要删除的结点过程中,

p2也移动,始终指向p1的前一个结点。第54页/共86页应考虑以下情况:1、删除的结点是第1个结点。if(num==p1->num)

//找到了

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

//是第1个结点要删的是第1个结点,则应将p1->next赋给head。head指向原来的第2个结点。第1个结点虽然仍存在,但它已与链表脱离,因为链表中从头指针开始无法访问到它。第55页/共86页p2->next原来指向p1指向的结点(图中第2个结点),现在p2->next改为指向p1->next所指向的结点(图中第3个结点)。p1所指向的结点不再是链表的一部分。2、删除的结点不是第1个结点if(num==p1->num)

//找到了

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

elsep2->next=p1->next;}第56页/共86页还需要考虑链表是空表(无结点)和链表中找不到要删除的结点的情况。第57页/共86页删除结点的函数del://参数是表头,和要删除的关键字。structstudent*del(structstudent*head,longnum){structstudent*p1,*p2;

if(head==NULL){printf(“\nlistnull!\n”);gotoend;}//空表

p1=head; while(num!=p1->num&&p1->next!=NULL)//没找到非表尾{p2=p1;p1=p1->next;}//如何实现p2指向p1前一个指针?

if(num==p1->num)

//找到了

{if(p1==head)head=p1->next;//是第一个结点

elsep2->next=p1->next;//是非一个结点

printf(“delete:%ld\n”,num); n=n-1;

free(p1);}elseprintf("%ldnotbeenfound!\n",num);end:return(head);}第58页/共86页11.7.7对链表的插入操作对链表的插入是指将一个结点插入到一个已有的链表中。为了能做到正确插入,必须解决两个问题:①怎样找到插入的位置;②怎样实现插入。第59页/共86页5head61015null128先看下面一个简单的例子:如图所示的链表:它是按结点中的整数域从小到大排序的。现在要插入一个结点,该节点中的数为10。待插入结点此结点已插入链表设在链表中,各结点按成员num(学号)由小到大顺序存放,把结点p0插入链表。用指针p0指向待插入结点,设把p0插在p1结点之前,插入算法:设三个指针变量p0、p1、p2,

p0指向待插入结点,p0插在p2后,p1前。p0p1p2第60页/共86页开始时只有p0和p1p0指向待插入结点p1=head1、p0->num>p1->num,说明位置还应在后。移动p1=p1->next直到p0->num<=p1->num

2、p0现在该插在p1前。右链扣有了,左链扣?需要一个p2,标志p1的上1个位置。1、如何找到应插入的位置为什么需要三个指针变量p0、p1、p2?{p2=p1; p1=p1->next;}第61页/共86页

structstudent*p0,*p1,*p2;p1=head;p0=stud;if(head==NULL){head=p0;p0->next=NULL;}else

{while((p0->num>p1-num)&&(p1->next!=NULL)){p2=p1;p1=p1->next;}实际上,插入的位置还有两个特殊情况,在表头和表尾。第62页/共86页2、如何插入:(1)一般情况插在中间:在p1之前、p2之后插入p0第63页/共86页(2)将p0插入第一个结点之前

当p0->num比第一个结点num还小,或者就是一个空链表。注意:此时不需用到p2。第64页/共86页(3)将p0插入表尾结点之后当搜遍全表都没发现比p0->num小的情况,说明应插在表尾。第65页/共86页第66页/共86页structstudent*insert(structstudent*head,structstudent*stud){structstudent

*p0,*p1,*p2;

p1=head;p0=stud;

if(head==NULL)

{head=p0;p0->next=NULL;}//空表,插第1个

else{while((p0->num>p1-num)&&(p1->next!=NULL)){p2=p1;p1=p1->next;}//在找p0->num<p1-num

if(p0->num<=p1->num)//找到了p0->num<p1-num{if(head==p1)head=p0;//找到的是表头,插在表头前

elsep2->next=p0;//找到的非表头,插在p2、p0间

p0->next=p1;}else//没找到p0->num<p1-num,插表尾

{p1->next=p0;p0->next=NULL;}}n=n+1;returnhead;}第67页/共86页main(){structstudent*head,stu;longdel_num;printf("inputrecords:\n");

head=creat();print(head);printf("\ninputthedeletednumber:");scanf("%ld",&del_num);

head=del(head,del_num);print(head);printf("\ninputtheinsertednumber:");scanf("%ld,%f",&stu.num,&stu.score);

head=insert(head,&stu);print(head);}第68页/共86页问题二:学校人员管理的问题问题设计一个简单的学校人员管理程序。人员包括教师、学生。问题分析数据结构:人员的信息仍用结构体变量来保存。在每一个结构体变量中,所有的数据成员都要单独占用一个存储空间。但是,有些问题中,数据成员并不要同时出现、使用。namenumsexjobclasspositionLiWang10112086FMST501prof解决方法:共用体第69页/共86页11.8共用体

有时需要将几个不同时出现的变量共享一个内存单元,如:将一个整型变量、实型变量、字符型变量共同放入同一个地址空间(当然这几个变量不能同时用),怎么办?

C提供了构造类型——共用体(联合体)类型支持。union联合名{

类型标识符成员名;类型标识符成员名;

…………….};例uniondata{inti;charch;floatf;};fchi类型定义不分配内存一、定义共用体类型第70页/共86页形式一:uniondata{inti;charch;floatf;}a,b;形式二:uniondata{inti;charch;floatf;};uniondataa,b,c,*p,d[3];形式三:union{inti;charch;floatf;}a,b,c;二、定义共用体变量第71页/共86页三、共用体变量特点:几个成员共用一段内存。引申1:共用体变量的内存长度是多少?

最长成员所占字节数。引申2:共用体变量几个成员能同时存在吗?不能。一个时刻只有一个成员存在。否则会被覆盖。引申3:共用体变量成员不能同时存在,那当前起作用的是谁?起作用的成员是最后一次存放的成员fchifchiab结构体变量定义分配内存,长度=最长成员所占字节数结构体变量任何时刻只有一个成员存在第72页/共86页四、共用体和结构体的比较:

例如:结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。共用体变量所占的内存长度等于最长的成员的长度。structdata{inti;charch;floatf;}a;uniondata{inti;charch;floatf;}a;“结构体”变量a:各成员同时存在占2+1+4=7个字节。“共用体”变量a任一时刻只有一个成员存在占4个字节(一个实型占4个字节)achfiachfi第73页/共86页引用方式:例a.i=1;a.ch=‘a’;a.f=1.5;printf(“%d”,a.i);(编译通过,运行结果不对)

引用规则不能引用共用体变量,只能引用其成员共用体指针名->成员名共用体变量名.成员名(*共用体指针名).成员名uniondata{inti;charch;floatf;};uniondataa,b,c,*p,d[3];a.ia.cha.fp->ip->chp->f(*p).i(*p).ch(*p).fd[0].id[0].chd[0].f共用体变量中起作用的成员是最后一次存放的成员例union{inti;charch;floatf;}a;a=1;()

不能在定义共用体变量时初始化例union{inti;charch;floatf;}a={1,’a’,1.5};()

可以用一个共用体变量为另一个变量赋值例floatx;union{inti;charch;floatf;}a,b;a.i=1;a.ch=‘a’;a.f=1.5;b=a;()x=a.f;()五、共用体变量引用第74页/共86页六、共用体变量和结构体可相互嵌套七、共用体应用struct{intnum;charname[10];charsex;charjob;

union{intclass;charposition[10];}category;}person[2];namenumsexjobclasspositionLiWang10112086FMST501prof例设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中。前4项是相同的。最后1项根据成员job取不同值,共用体。第75页/共86页

循环n次读入姓名、号码、性别、职务job==‘s’真真假假读入class读入position输出“输入错”循环n次job==‘s’真假输出:姓名,号码,性别,职业,班级输出:姓名,号码,性别,职业,职务job==‘t’struct{intnum;charname[10];charsex;charjob;

union{intclass;charposition[10];}category;}person[2];第76页/共86页voidmain(){

inti;

for(i=0;i<2;i++){

scanf("%d%s%c%c",&person[i].num,&person[i].name,

&person[i].sex,&person[i].job);//输入除班级/职务外的数据

if

(person[i].job==‘S’)//根据person[i].job判断是学生

scanf(“%d”,&person[i].category.banji);

elseif(person[i].job==‘T’))//根据person[i].job判断是教师

scanf("%s",person[i].category.position);

else

printf(“Inputerror!”);}

prin

温馨提示

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

评论

0/150

提交评论