C语言编程技巧分析 教学课件 kj第8章 结构体共用体和枚举类型以及链表编程技巧分析_第1页
C语言编程技巧分析 教学课件 kj第8章 结构体共用体和枚举类型以及链表编程技巧分析_第2页
C语言编程技巧分析 教学课件 kj第8章 结构体共用体和枚举类型以及链表编程技巧分析_第3页
C语言编程技巧分析 教学课件 kj第8章 结构体共用体和枚举类型以及链表编程技巧分析_第4页
C语言编程技巧分析 教学课件 kj第8章 结构体共用体和枚举类型以及链表编程技巧分析_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

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

文档简介

在线教务辅导网:://教材其余课件及动画素材请查阅在线教务辅导网QQ:349134187

或者直接输入下面地址:第8章结构体、共用体和枚举类型以及链表编程技巧分析C语言编程技巧分析本章概述本章首先简单介绍结构体、共用体和枚举类型以及链表的相关知识,接着详细讲解运用结构体、共用体和枚举类型以及链表知识时需要注意的问题,并通过实例分析运用结构体、共用体和枚举类型以及链表知识的一些编程技巧。本章的学习目标本章教学目的:

掌握结构体、共用体和枚举类型以及链表知识;理解运用结构体、共用体和枚举类型以及链表知识时需要注意的一些问题;掌握结构体、共用体和枚举类型以及链表知识的相关编程技巧。本章教学重点:

运用结构体、共用体和枚举类型以及链表知识需注意的问题和编程技巧。本章教学难点:

关于结构体、共用体和枚举类型以及链表知识的编程技巧。8.1结构体、共用体和枚举类型以及链表知识简要介绍8.2运用结构体、共用体和枚举类型以及链表知识时需要注意的问题8.3结构体、共用体和枚举类型以及链表知识编程技巧分析本章主要内容8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.1结构体1、结构体类型的声明struct结构体名{

成员项表列;};例如:structSTU/*声明一个结构体类型,名称是structSTU*/{longxh[11];/*xh是一个成员,存放学号*/charxm[20];/*xm是一个成员,存放姓名*/charbj[20];/*bj是一个成员,存放班级*/floatcj[3];/*cj是一个成员,存放三科考试成绩*/};8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.1结构体2、结构体类型变量的定义结构体类型变量的定义可以有以下三种形式:(1)先声明结构体类型,再定义结构体类型的变量。例如利用上面的structSTU结构体类型,可以在下面定义structSTU类型的变量:structSTUstudent1,student2(2)声明结构体类型同时定义结构体类型变量:structDATE/*日期结构体类型*/{intday;

intmonth;

intyear;}time1,time2;/*定义两个structDATE类型变量*/8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.1结构体(3)直接定义结构体类型变量:struct{floatre;/*复数的实部*/floatim;/*复数的虚部*/}a,b;/*定义两个复数型变量*/3、结构体成员的引用结构体成员的引用格式如下:<结构体类型变量名>.<成员名>如:a.re=2;a.im=2.5;time1.day=23;time2.month=12;strcpy(student1.xm,〞张三〞);8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.1结构体4、结构体类型变量的初始化上述对结构体类型变量的三种定义形式均可在定义时初始化,例如:structSTUstudent={1213012,"李强","英语1班",98.5,97.4,95};5、结构体类型的数组结构体类型数组的定义与其它数据类型数组的定义方式一样,例如:structSTUclass[50];

/*定义一个50个元素的结构体数组*/引用结构体类型数组元素的成员的格式:<结构体类型数组名><[下标]>.<成员>例如:class[i].xm表示第i个学生的姓名,

class[i].bj表示第i个学生的班级。

8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.1结构体6、结构体类型的指针变量结构体类型的指针变量的定义格式如下:struct

结构体类型名*变量名;例如:structSTUstudent1,*p=&student1;可以通过结构体指针变量间接访问结构变量的各个成员。其访问的格式为:(*结构体指针变量).成员名或结构体指针变量->成员名例如:(*p).xh

或者p->xh

等价于student1.xh

注意:(*p)两侧的括号不可少。8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.2共用体1、共用体类型的声明和共用体类型变量的定义共用体类型的声明与结构体类型的声明类似,格式如下:union共用类型名{成员列表};共用变量的定义与结构变量的定义类似,三种格式如下:直接定义:

间接定义:

省略类型名直接定义:union共用体名union共用体名

union{成员列表{成员列表};

{成员列表}变量列表;

union共用体名变量列表;}变量列表;

8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.2共用体2、共用体变量的引用引用形式与结构体变量一样,只能逐个引用共用体变量的成员。注意:不能对共用体变量进行整体的输入或输出。假设a是共用体类型变量,那么下面语句都是错误的:scdanf(“%d〞,&a);printf(“%d〞,a);访问共用体类型变量a成员的格式与访问结构体变量成员格式相同,假设i是a的一个int型成员,那么下面的输入或输出格式是正确的:scanf(“%d〞,&a.i);printf(“%d\n〞,a.i);8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.2共用体3、共用体与结构体相似之处〔1〕都是由不同类型的数据项组合在一起;〔2〕都只能对分量进行操作和引用。4、共用体变量的特点〔1〕系统采用覆盖技术,实现共用体变量各成员的内存共享,所以在某一时刻,存放在内存中的和起作用的是最后一次存入的成员值。共用体变量占用的内存空间,等于最长的成员的长度,而不是各成员长度之和。〔2〕由于所有成员共享同一内存空间,故共用体变量的地址与各成员的地址相同。〔3〕不能对共用体变量进行初始化〔而结构体变量可以初始化〕;也不能将共用体变量作为函数参数,以及使函数返回一个共用体数据,但可以使用指向共用体变量的指针。〔4〕共用类型可以出现在结构类型定义中,反之亦然。8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.3枚举类型1、枚举类型的声明enum枚举类型名{取值表};例如enumweekdays{Sun,Mon,Tue,Wed,Thu,Fri,Sat};上面括号中的标识符称为枚举常量。它只能为标识符,不能为数字常量或字符常量。2、枚举变量的定义枚举变量的定义与结构体变量类似,有下面一些定义形式:〔1〕间接定义,例如:enumweekdaysw1,w2;〔2〕直接定义,例如:enumweekdays{Sun,……}w1,w2;〔3〕省略类型名直接定义枚举变量,例如:enum{Sun,Mon,Tue,Wed,Thu,Fri,Sat}w3,w4;8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.4链表链表是动态地进行存储分配的一种结构,链表中的数据在内存中不必连续存放,数据之间通过指针链接起来,相比于数组结构,链表的插入和删除操作比较方便。1、链表中的结点链表中的结点是结构体类型的数据,每个结点的所有成员分为两局部,一局部用来存放数据〔各种实际的信息〕,如编号、姓名和年龄等;另一局部存放指针,用来连接其它结点。例如:定义了一个结构体类型变量a,成员num、name和score用来存放数据〔各种实际的信息〕,成员next用来存放指针〔指向下一个结点的首地址〕。structNODE{intnum;charname[10];intage;structNODE*next;}a;8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.4链表2、链表的种类:〔1〕单向链表:每个结点除了一些数据成员外,只包含一个指针成员。单向链表通常有一个头指针〔head),用于指向链表头。单向链表有一个尾结点,尾结点的指针成员存放的是空指针〔NULL〕。〔2〕循环链表:最后一个结点的指针指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。〔3〕双向链表:结点除含有数据成员外,还有两个指针成员,一个指针成员存储直接后继结点地址;另一个指针成员存储直接前驱结点地址。8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.4链表3、单向链表的根本操作:〔1〕创立链表:从无到有地建立起一个链表,即往空链表中依次插入假设干结点,并保持结点之间的前驱和后继关系。〔2〕查找结点:按给定的结点索引号或查找条件,查找某个结点。〔3〕插入操作:在结点a与b之间插入一个新的结点d。〔4〕删除操作:将结点a与b之间的结点d删除。〔5〕打印输出:输出结点的数据成员值。8.1结构体、共用体和枚举类型以及链表知识简要介绍8.1.4链表4、处理动态链表所需的函数:〔1〕void*malloc(unsignedintsize);作用:在内存的动态存储区中分配一个长度为size的连续空间。〔2〕void*calloc(unsignedn,unsignedsize);作用:在内存动态区中分配n长度为size的连续空间。〔3〕void*realloc(void*mem_address,unsignedintnewsize);作用:扩大mem_address指向的内存块的大小为newsize。〔4〕voidfree(void*p);作用:释放由p指向的内存区。8.2运用结构体、链表等知识时需要注意的问题关于结构体和共用体的类型声明〔1〕区分开类型名与变量名结构体类型名和结构体变量名是两个不同的概念,不能混淆。结构体类型名只能表示一个结构形式,编译系统并不对它分配内存空间。只有当某变量被说明为这种类型的结构时,才对该变量分配存储空间。〔2〕结构体与共用体可以相互引用C语言在声明某个结构体类型或共用体类型时,可以使用已经声明过的结构体、共用体类型。结构体类型中可以有共用体类型的成员,共用体类型中可以有结构体类型的成员。例如:8.2运用结构体、链表等知识时需要注意的问题关于结构体和共用体的类型声明structdata{intday;intmouth;intyear;};structperson{charname[20];structdatabirthday;/*成员birthday的类型structdata已经在前面声明过*/union{chardepartment[50];/*假设为教师身份时,成员category为department*/intclass;/*假设为学生身份时,成员category为class*/}category;/*成员category是共用体类型*/}x;8.2运用结构体、链表等知识时需要注意的问题关于结构体和共用体的类型声明〔3〕typedef与结构体的联合应用使用typedef命令可以取一个新的类型名来代替已有的类型名,一般当有复杂类型定义时,如定义结构体类型、共用体类型时,常常用typedef为刚定义的复杂类型取一个较为简单、直接的类型名。例如:typedefstructnode{longnum;charname[10];structnode*next;}NODE,*LINK;

8.2运用结构体、链表等知识时需要注意的问题关于结构体和共用体的类型声明上面声明了一个内容与structnode相同但名为NODE的结构体类型名,还声明了一个结构体指针类型LINK。注意,LINK不是指针变量,而是一个指针类型。以下定义变量的形式都正确:

structnodestu1,*p;/*定义结构体变量stu1和指针变量p*/NODEstu2,*q;/*定义结构体变量stu2和指针变量q*/LINKr;/*定义结构体指针变量r*/8.2运用结构体、链表等知识时需要注意的问题关于结构体和共用体的类型声明〔4〕不能递归定义在定义链表的结点类型时常常用结构体类型本身去定义一个指针分量,如前面例子中的next分量,通过这个分量,使链表中的结点链接起来,这是允许的,也是必须的。但是绝对不能用结构体类型自己去定义自己的一个非指针类型分量,也就是不能递归定义。如下是错误的:structnode{……;structnodenext;};

8.2运用结构体、链表等知识时需要注意的问题关于结构体、共用体变量的输入和输出结构体、共用体类型变量的输入和输出,必须采用变量的各成员独立输入输出,而不能将结构体、共用体类型变量以整体的形式输入输出。可以通过C语言提供的输入输出函数完成对结构体、共用体类型变量成员的输入输出。结构体、共用体变量各成员的数据类型通常是不一样的,为了统一输入过程,可以先将变量的各成员均以字符串形式输入,然后利用C语言的类型转换函数将其转换为所需类型。8.2运用结构体、链表等知识时需要注意的问题关于结构体、共用体变量的输入和输出类型转换的函数是:int

atoi(char*str);/*转换str所指向的字符串为整型*/doubleatof(char*str);/*转换str所指向的字符串为实型,*/longatol(char*str);/*转换str所指向的字符串为长整型*/

使用上述函数,要包含头文件"stdlib.h"。对上述的结构体类型structnode的变量student的成员输入采用的一般形式:chartemp[20];

gets(student.xm);/*输入结构体变量的成员xm的值*/gets(temp);student.xh=atol(temp);/*转换为长整型后赋值*/for(i=0;i<3;i++)

{gets(temp);

student.cj[i]=atoi(temp);/*转换为整型后赋值*/}8.2运用结构体、链表等知识时需要注意的问题关于共用体与结构体的主要区别〔1〕结构体变量占用空间是各成员所占空间之总和;共用体变量占存储空间是各成员中所占空间最大者。〔2〕结构体变量各成员占用内存中一片连续的存储区,各成员的地址互不相同;共用体变量各成员在内存中所占空间的起始地址相同。〔3〕结构体变量的各个分量在任何时刻都同时存在,且可同时引用。共用体变量的各个分量在某一时刻只存在其中一个,也只能引用其中的一个。〔4〕结构体变量可以初始化,共用体变量不能初始化。8.2运用结构体、链表等知识时需要注意的问题8.2.4关于结构体与函数〔1〕结构体作函数参数将一个结构体变量的值传递给另一个函数,可以采用两种方式:用结构体变量作参数,形参与实参都用结构体变量,参数传递时直接将实参结构体变量的各个成员的值全部传递给形参的结构体变量。注意:这种方式是按传值方式传递参数的,函数中形参结构体变量的修改不影响实参结构体变量的值;这种方法要将全部成员值一个一个传递,开销大,因此一般不采用。用指向结构体的指针作函数参数,形参为结构体类型的指针变量,实参为结构体变量〔或数组〕的地址或指向结构体变量〔数组〕的指针。这种方式只传递地址,不传递结构体变量的值,克服了第一种方法的缺点,实际编程中被较多采用。8.2运用结构体、链表等知识时需要注意的问题关于结构体与函数〔2〕结构体作函数的返回值与结构体作函数参数相类似,既可以设置函数的返回值为结构体类型的,也可以设置函数的返回值为结构体指针类型的。前者在运行时会有较多的数据复制,不利于提高程序的效率;后者只传递指针,开销小,效率高,多为程序设计者所采用。8.2运用结构体、链表等知识时需要注意的问题8.2.5关于枚举类型〔1〕枚举类型仅适用于取值有限的数据。例如:1周的7天,1年的12个月。〔2〕取值表中的值为枚举元素,其含义由程序解释。例如,不是写成“Sun〞就自动代表“星期天〞。事实上,枚举元素用什么表示都可以。〔3〕枚举类型变量w1,w2只能在定义的取值表中取其中一个枚举常量作为当前值。〔4〕枚举元素作为常量是有值的,假设无特殊规定,枚举元素的值是定义时的顺序号。定义时的顺序号,从0开始,依次增1。所以枚举元素可以进行比较,比较规那么是:序号大者为大。例如,上例中的Sun=0、Mon=1、……、Sat=6,所以Mon>Sun、Sat最大。8.2运用结构体、链表等知识时需要注意的问题关于枚举类型〔5〕枚举元素的值也是可以改变的。可以由程序指定,例如:enumweekdays{Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat};那么Sun=7,Mon=1,从Tue=2开始,依次增1。〔6〕一个整型数值不能直接赋值给一个枚举变量。enumweekdays{Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat};enumweekdayswk1;不允许直接赋值整数:wk1=7;/*数据类型不同*/只能写成:wk1=Sun;或wk1=(enumweekdays)7;甚至可以是表达式,如:w2=(enumweekday)(5-3);8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析例8.1用结构体类型描述一个一元二次方程〔ax2+bx+c=0〕,并编写一个求其根的函数。程序如下:#include"stdio.h"#include"math.h"structfaction{floata;floatb;floatc;floatx1,x2;};intjie(structfaction*f){floatdel;del=(f->b)*(f->b)-4*(f->a)*(f->c);if(del>=0){f->x1=(-f->b+sqrt(del))/(2*f->a);f->x2=(-f->b-sqrt(del))/(2*f->a);return1;}elsereturn0;}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析main(){structfactionf1;intresult;printf("请输入一个一元二次方程的三个系数");scanf("%f%f%f",&f1.a,&f1.b,&f1.c);result=jie(&f1);if(result=1)printf("x1=%f,x2=%f\n",f1.x1,f1.x2);elseprintf("无实数解");}分析:这个例子通过一个结构体把一个一元二次方程相关的数据都封装在一起,然后通过相应的函数操作此数据对象,已具备初步的面向对象程序设计的思想。注意两种引用结构体成员的方法,在main函数中对f1成员的引用直接用f1.x1、f1.x2,而在jie函数中由于f是指针变量,故引用的方法是f->x1、f->x2等等。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析例8.2输入3名学生信息〔信息包括学号、姓名和计算机成绩〕。然后输出这3名学生信息,最后将其中成绩最高的学生全部信息显示在屏幕上。程序如下:第1种方法:使用普通的结构体变量,每个学生的信息存放在一个变量中。#include<stdio.h>structstudents{longno;charname[10];intscore;};main(){structstudentss1,s2,s3,max;scanf("%ld%s%d",&s1.no,,&s1.score);scanf("%ld%s%d",&s2.no,,&s2.score);scanf("%ld%s%d",&s3.no,,&s3.score);8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析printf("%d%s%4d\n",s1.no,,s1.score);printf("%d%s%4d\n",s2.no,,s2.score);printf("%d%s%4d\n",s3.no,,s3.score);max=s1;if(max.score<s2.score)max=s2;if(max.score<s3.score)max=s3;printf("Thestudentwithmaxscoreis:\n");printf("%d%10s%4d\n",max.no,,max.score);}

第2种方法:使用指针变量,找出其中成绩最高的学生。程序的前面不动,只是定义指针变量p代替上面的max,程序修改如下:8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析structstudents*p;…printf("%d%s%4d\n",s3.no,,s3.score);p=&s1; if(p->score<s2.score)p=&s2;if(p->score<s3.score)p=&s3;printf("Thestudentwithmaxscoreis:\n");printf("%d%10s%4d\n",p->no,p->name,p->score);…8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析分析:在程序中可以看到,对结构体变量赋值时,必须对其每一个分量赋值〔定义时初始化例外〕。但同结构的结构体变量之间可以整体赋值,这与数组的操作完全不同。输出结构体变量时也只能通过输出其中的每一个成员来实现,不能整体输出。对结构体类型数据的根本操作,例如求平均值、最大值、最小值、排序等,算法与简单型数据的算法是一样的,只是操作时针对结构体类型数据中的某一个成员而已。针对上面的例子,请读者自己完成求三个学生平均分的操作,以及完成成绩从高到低输出的操作。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析例8.3修改例8.2,输入100名学生信息〔信息包括学号、姓名和计算机成绩〕,然后输出这100名学生信息。最后编写一函数,求出其中成绩最高的学生,通过函数调用输出此成绩最高的学生信息。程序如下:#include<stdio.h>structstudents{longno;charname[10];intscore;};#defineN100intfind(structstudentsa[],intn){intp=0,i;for(i=1;i<n;i++)if(a[i].score>a[p].score)p=i;returnp;}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析main(){structstudentss[N],max;for(inti=0;i<N;i++)scanf("%ld%s%d",&s[i].no,s[i].name,&s[i].score);for(i=0;i<N;i++)printf("%10d%10s%4d\n",s[i].no,s[i].name,s[i].score);max=s[find(s,N)];printf("Thestudentwithmaxscoreis:\n");printf("%10d%10s%4d\n",max.no,,max.score);}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析分析:有100个学生,自然不能再用100个变量描述,需设置结构体数组完成。结构体数组作函数的参数用法与其他类型数组作函数参数一样。函数返回值的设置,可以把成绩最高学生的结构体整体设为返回值,也可以只返回他在数组中的下标,也可以返回指向他的指针。考虑到整体返回要进行相应的数据复制,需要较大的系统开销,因此选择返回下标。函数的参数和返回值都可能设置为结构体类型的指针变量,请读者自己修改完成。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析例8.4模拟一个井字棋双人对战游戏。井字棋游戏的棋盘是一个2*2的格子,棋子下在交叉点上,交叉点正好是3行3列,最早连成3个棋子成一线的一方获胜。程序如右:structposition{intx;inty;};intqipan[3][3]={0};/*棋盘数据结构*/voidprintqipan(intqp[3][3])/*打印棋盘*/{inti;for(i=0;i<3;i++){if(qp[i][0]==0)printf("+--");elseif(qp[i][0]==1)printf("o--");elseprintf("*--");if(qp[i][1]==0)printf("+--");elseif(qp[i][1]==1)printf("o--");elseprintf("*--");if(qp[i][2]==0)printf("+");elseif(qp[i][2]==1)printf("o");elseprintf("*");printf("\n");}}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析intcheck(structposition*play,inti)/*检测有无3个棋子连成一线*/{intk;intx=play[i].x;inty=play[i].y;intqizi=qipan[x][y];for(k=0;k<=2;k++)*/检查所在行是否都是同一棋子*/if(qipan[x][k]!=qizi)break;if(k>2)return1;for(k=0;k<=2;k++)*/检查所在列是否都是同一棋子*/if(qipan[k][y]!=qizi)break;if(k>2)return1;for(k=0;k<=2;k++)*/检查所在对角线是否都是同一棋子*/if(qipan[k][k]!=qizi)break;if(k>2)return1;for(k=0;k<=2;k++)*/检查所在反对角线是否都是同一棋子*/if(qipan[k][2-k]!=qizi)break;if(k>2)return1;return0;}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析if(check(play1,i)){printf("1号选手胜利了");return;}if(num==9)break;/*最多只有9个位置*/do{printf(“选手2输入下子的位置:");scanf("%d,%d",&t_x,&t_y);}while(qipan[t_x][t_y]!=0);play2[i].x=t_x;play2[i].y=t_y;qipang[t_x][t_y]=2;num+=1;printqipan(qipan);if(check(play2,i)){printf("2号选手胜利了");return;}i++;}printf("两人都失败了");}main(){inti,num=0,t_x,t_y;structpositionplay1[5],play2[5];/*每个选手最多下5次*/printqipan(qipan);i=1;while(num<9){do{printf("选手1输入下子的位置:");scanf("%d,%d",&t_x,&t_y);}while(qipan[t_x][t_y]!=0);play1[i].x=t_x;play1[i].y=t_y;qipan[t_x][t_y]=1;num+=1;printqipan(qipan);8.3结构体、共用体和枚举类型以及链表编程技巧分析关于结构体知识编程技巧分析〔1〕棋盘的模拟。因为棋盘上的交叉点正好是3行3列,因此用一个3行3列的二维数组即可。数组元素初始值为0,表示未有棋子落下;值为1表示落下的是1号选手棋子,值为2表示落下的是2号选手的棋子。〔2〕是否连成一线的检测。对刚落下的棋子检查所在行是否都是同一个选手的棋子;同样再检测所在列是否都是同一选手的棋子;同样的方法再检测对角线和反对角线。〔3〕对棋子位置的描述。用一个结构体,把棋子所在的行号和列号组合在一起。程序中对连成一线的检测是从棋盘的角度出发,检测有没有相同值的行、列、对角线,我们也可从选手已下的棋子,即play1、play2数组出发,检测是否有3个的同值的行号分量或列号分量。程序请读者编写。8.3结构体、共用体和枚举类型以及链表编程技巧分析8.3.2关于共用体和枚举类型知识编程技巧分析例8.6有一个教师与学生通用的表格,教师有姓名、年龄、类型、教研室四项数据。学生有姓名、年龄、类型、班级四项数据。输入所有教师和学生的数据,再以表格形式输出。程序如下:#include<stdio.h>#defineN100/*设教师和学生共有N个*/unionc_t{intclassno;/*学生班级号*/charoffice[10];/*教师教研室名*/};structStu_Tea

{charname[10];/*姓名*/intage;/*年龄*/inttype;/*类型*/unionc_tdepart;/*教研室名或班级号*/};8.3结构体、共用体和枚举类型以及链表编程技巧分析关于共用体和枚举类型知识编程技巧分析voidmain(){structStu_Teabody[N];inti,k;for(i=0;i<N;i++)/*输入学生或教师信息*/{printf("输入姓名、年龄\n");scanf("%s%d",body[i].name,&body[i].age);printf("假设此人是教师,类型请输入1;假设此人是学生,类型请输入0。\n");scanf("%d",&body[i].type);if(body[i].type==1)/*此人是教师,输入教研室名*/{printf("输入教研室名\n");scanf("%s",body[i].depart.office);}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于共用体和枚举类型知识编程技巧分析if(body[i].type==0)/*此人是学生,输入班级号*/{printf("输入班级号\n");scanf("%d",&body[i].depart.classno);}}printf("姓名、年龄、教研室或班级\n");/*显示学生、教师信息*/for(i=0;i<N;i++){if(body[i].type==0)printf("%s\t%4d%4d\n",body[i].name,body[i].age,body[i].depart.classno);if(body[i].type==1)printf("%s\t%4d%s\n",body[i].name,body[i].age,body[i].depart.office);}}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于共用体和枚举类型知识编程技巧分析分析:以上程序中,结构体中的一个成员depart的类型是共用体,对于类型是学生或教师,可以选取不同的共用体成员。变量的引用是通过成员引用符“.〞实现的,同结体变量的引用一样,也可以通过共用体指针变量引用,同样,需要使用“->〞运算符实现。在计算机硬件编程中,尤其是单片机的C语言编程中,当需要访问存放器时,经常会通过共用体类型变量来定义存放器,进一步的学习请读者查阅相关资料。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于共用体和枚举类型知识编程技巧分析例8.7口袋中有红、黄、蓝、白、黑5种颜色的球假设干个。每次从口袋中先后取出3个球,问得到3种不同色的球的可能取法,输出每种可能取法排列的情况。程序如下:#include<stdio.h>main(){enumcolor{red,yellow,blue,white,black};/*声明枚举类型color*/enumcolori,j,k,pri;intn=0,loop;/*定义枚举变量*/for(i=red;i<=black;i++)/*逐个检查是否符合条件*/for(j=red;j<=black;j++)if(i!=j){for(k=red;k<=black;k++)8.3结构体、共用体和枚举类型以及链表编程技巧分析关于共用体和枚举类型知识编程技巧分析

if((k!=i)&&(k!=j)){n=n+1;printf("%-4d",n);for(loop=1;loop<=3;loop++){switch(loop) {case1:pri=i;break;case2:pri=j;break;case3:pri=k;break;default:break;}switch(pri){casered:printf("%-10s","red");break;caseyellow:printf("%-10s","yellow");break;caseblue:printf("%-10s","blue");break;casewhite:printf("%-10s","white");break;caseblack:printf("%-10s","black");break;default:break;}}printf("\n");}}printf("\ntotal:%5d\n",n);}8.3结构体、共用体和枚举类型以及链表编程技巧分析8.3.2关于共用体和枚举类型知识编程技巧分析

分析:每个球只能是5种色之一,而且要判断各球是否同色,所以用枚举类型变量处理。程序采用穷举法,设取出的球为i、j、k。根据题意,i、j、k分别是5种色球之一,并要求i≠j≠k。通过三重循环把每一种组合都试一下,看哪一组符合条件。8.3结构体、共用体和枚举类型以及链表编程技巧分析8.3.3关于链表知识编程技巧分析例8.8从键盘输入假设干个非零整数作为结点的数据元素,创立单向链表。程序如下:#include"stdio.h"#include"stdlib.h"#include"malloc.h"structLnode{intdata;structLnode*next;}*p,*q,*head;/*p为跟踪表尾的指针,q为指向新结点的指针,head是指向头结点的指针*/8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析main(){inttemp;head=(structLnode*)malloc(sizeof(structLnode));if(head==NULL){printf("memoryallocatingerror!");exit(0);}head->next=NULL;p=head;printf("inputainteger:");scanf("%d",&temp);while(temp!=0){q=(structLnode*)malloc(sizeof(structLnode));if(q==NULL){printf("memoryallocatingerror!");exit(0);}q->data=temp;q->next=NULL;p->next=q;p=q;printf("inputainteger:");scanf("%d",&temp);}}8.3结构体、共用体和枚举类型以及链表编程技巧分析8.3.3关于链表知识编程技巧分析分析:〔1〕为了简化链表操作中对表中有结点和无结点的情况处理,一般会在链表中增加一个结点,作为链表的第一个结点,但该结点不存放数据元素,特称之为头结点。头结点的指针成员存放下一个数据元素结点的首地址。〔2〕首先建立一个有一个头结点的单向链表,采用每次在链表的尾部增加一个结点的方式,将数据元素结点链接起来。由于新结点是添加在单向链表的尾部,故需要设置一个指向表尾的指针,且每添加一个新结点就要更新此指针。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析上述程序建立起来的单链表数据的顺序正好与输入的顺序一致。如果对数据的顺序不作要求,那么可以把新结点添加在链表的头部,这样就不需要跟踪表尾指针,新建链表的效率更高。程序如下:#include"stdio.h"#include"stdlib.h"#include"malloc.h"structLnode{intdata;structLnode*next;}*q,*head;main(){inttemp;head=(structLnode*)malloc(sizeof(structLnode));8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析if(head==NULL){printf("memoryallocatingerror!");exit(0);}head->next=NULL;printf("inputainteger:");scanf("%d",&temp);while(temp!=0){q=(structLnode*)malloc(sizeof(structLnode));if(q==NULL){printf("memoryallocatingerror!");exit(0);}q->data=temp;q->next=head->next;head->next=q;printf("inputainteger:");scanf("%d",&temp);}}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析例8.9单向链表有10个结点,各结点的数据成员data的值分别是1、3、5、7、9、11、13、15、17、19。将一个新结点插入到该单向链表的第i个结点位置上〔头结点之后的第一个元素序号为1〕。程序如下:#include"stdio.h"#include"malloc.h"structnode{intdata;structnode*next;};8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析structnode*insert(structnode*head,inti,intnewdata){structnode*q,*p;intj;if(i<0){printf("插入位置不存在");returnhead;}q=(structnode*)malloc(sizeof(structnode));q->data=newdata;p=head->next;j=1;while(p!=NULL&&j<i-1){j++;p=p->next;}if(p!=NULL){q->next=p->next;p->next=q;}returnhead;}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析main(){structnode*head,*newnode,*rear;inti,x;head=(structnode*)malloc(sizeof(structnode));head->next=NULL;

rear=head;for(i=1;i<=10;i++){newnode=(structnode*)malloc(sizeof(structnode));newnode->data=2*i-1;/*原链表的数据为1,3,5,7……*/newnode->next=NULL;

rear->next=newnode;

rear=newnode;}printf("请输入新结点数据及插入的位置");scanf("%d%d",&x,&i);head=insert(head,i,x);printf("插入后的链表数据为:\n");for(structnode*p=head->next;p!=NULL;p=p->next)printf("%d-->",p->data);}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析分析:在p指针指向的结点插入之后,设新结点由指针q指向,那么插入的过程为:q->next=p->next;p->next=q;这种方法的关键之处是先要找到p的位置。由于新结点是插入在第i个位置上,因此p应该是指向第i-1个结点的指针。上述算法需要先对链表进行一次遍历,如果问题中已告诉插入的位置为p指向的位置,能否不进行遍历,直接把新结点插入到p指针指向的位置呢?可以采用如下方法,将新结点插入在p指针指向的结点之前。首先分配一个结点q,将q插入在p后,接下来将p结点与q结点的数据域的值作一下交换。这种方法算法就不需要遍历链表了,效率高于前一方法。程序如下:8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析#include"stdio.h"#include"malloc.h"structnode{intdata;structnode*next;};voidinsert2(structnode*p,intnewdata){structnode*q;intt;q=(structnode*)malloc(sizeof(structnode));q->data=newdata;q->next=p->next;p->next=q;/*将q插入在p的后面*/t=p->data;p->data=q->data;q->data=t;/*交换p和q的data值*/return;}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析main(){structnode*head,*newnode,*rear;inti,x;head=(structnode*)malloc(sizeof(structnode));head->next=NULL;rear=head;for(i=1;i<=10;i++){newnode=(structnode*)malloc(sizeof(structnode));newnode->data=2*i-1;/*原链表为有序的数据为1,3,5,7……*/newnode->next=NULL;rear->next=newnode;rear=newnode;}printf("请输入新结点数据");scanf("%d",&x);for(structnode*p=head->next;p->data<x;p=p->next);insert2(p,x);printf("插入后的链表数据为:\n");for(p=head->next;p!=NULL;p=p->next)printf("%d-->",p->data);}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析例8.10编写函数,在单向链表中删除指定结点。给定一个特定值,假设单链表中某个数据结点的值与此特定值相同,那么删除该结点;假设不存在,那么给出提示信息。程序如下:#include"stdio.h"#include"stdlib.h"#include"malloc.h"structLNode{intnum;structLNode*next;};8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析structLNode*del(structLNode*head,longnum){structLNode*p,*q;if(head==NULL){printf("\nlistnull!\n");returnhead;}p=head;while(num!=p->num&&p->next!=NULL){q=p;p=p->next;}if(num==p->num){if(p==head)head=p->next;else{q->next=p->next;free(p);}printf("delete:%ld\n",num);}elseprintf("%ldnotbeenfound!\n",num);return(head);}关于链表知识编程技巧分析例8.10分析:〔1〕要删除特定值结点,需要先遍历单链表,找到待删除的位置。〔2〕删除指针变量p指向的结点,首先需要先得到p指向的结点的前面一个结点。因此,需要用指针变量q指向p所指向的结点的前面一个结点。〔3〕删除结点不仅要修改指针的指向,还要用free函数释放被删除结点所占据的内存。8.3结构体、共用体和枚举类型以及链表编程技巧分析8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析例8.11对于单向链表,设计一个函数,从尾到头反过来输出每个结点的值,要求不破坏单链表。程序如下:voidprint_node(structnode*head){if(head==NULL)return;else{print_node(head->next);printf("%d",head->data);}}分析:〔1〕如果允许破坏此单向链表,那么可以先把此单向链表倒置,再依次输出所有结点。这种方法简单明了,输出每个结点容易实现。〔2〕本程序用递归程序实现,利用递归算法可以使得输出倒序。8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析〔3〕用上述的递归程序需要屡次的函数调用,效率低下,可以考虑直接用堆栈的方法实现。先顺序依次访问单向链表,把读到的数据压入到堆栈中,全部读完后再从堆栈中弹出就可以反过来输出每个结点的值了。考虑到压栈、出栈的开销,可以用一个数组代替堆栈。程序如下:structnode{intdata;structnode*next;};voidprint_node(structnode*head){structnode*p=head->next;/*head指向的是头结点。p指向第一个元素。*/intstack[100];/*模拟堆栈,假定结点元素类型为整型,不超过100个结点*/inti=0;while(p!=NULL){stack[++i]=p->data;p=p->next;}while(i>0)printf(“%d,〞,stack[i--]);}8.3结构体、共用体和枚举类型以及链表编程技巧分析关于链表知识编程技巧分析例8.12编写函数,将两个有序的单向链表合并,要求在原有的结点根底上修改指针的指向,不产生新的结点。程序如下:structNode{intnum;structNode*next;};structNode*MergeList(structNode*head1,structNode*head2)/*按升序合并*/{structNode*head,*temp;if(head1==NULL)returnhead2;if(head2==NULL)returnhead1;if(head1->num<=head2->num){head=head1;head1=head1->next;}else

温馨提示

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

评论

0/150

提交评论