《C语言第7章结构体与共用体(重庆交大版).ppt》由会员分享,可在线阅读,更多相关《C语言第7章结构体与共用体(重庆交大版).ppt(99页珍藏版)》请在三一办公上搜索。
1、第7章 结构体与链表,7.1 结构体类型的定义7.2 结构体类型变量的定义、引用和实始化7.3 结构体数组7.4指针在结构体中应用7.5 结构体应用举例7.6 共用体7.7枚举类型7.8自定义数据类型7.9顺序表7.10链表,7.1 结构体类型的定义,结构体是具有不同类型的数据的有序集合结构体定义:struct 结构体类型名 类型标识符 成员名1;类型标识符 成员名2;类型标识符 成员名n;;,struct:定义结构体类型的关键字;域:结构体类型定义中的每1个成员;成员名的命名规则和变量相同,同一结构体的同层成员不可同名。,例:定义结构体类型student,struct student int
2、 num;char name20;char sex;int age;float score;char addr30;,struct student应作为一个整体对待,“;”号不能少!,7.2 结构体类型变量的定义、引用和初始化,结构体变量的定义 一、先定义结构体类型再定义变量名形式:struct 结构体名 结构体变量名表 例:在前面已定义结构体类型struct student 则可定义:struct student stu1,stu2;stu1,stu2即为struct student类型的变量,二、在定义类型的同时 定义变量一般形式为:struct 结构体名 成员表列 变量名表列;,stru
3、ct student int num;char name20;char sex;int age;float score;char addr30;student1,student2;,三、直接定义结构类型 的变量一般形式为:struct 成员表列 变量名表列;*不出现结构体名,structint num;char name20;char sex;int age;float score;char addr30;student1,student2;,结构体类型的嵌套,定义:结构体成员又是一个结构体变量例:struct date int month;int day;int year;struct st
4、udent char name20;char sex;int age;struct date birthday;stu1,stu2;,嵌套结构体变量的引用:点标记法只能对最低成员进行赋值或存取、运算。例:stu1.age=20;stu1.dirthday.month=7;stu1.dirthday.day=31;思考以下的引用 printf(“%d%d%d”,stu1.birthday);()stu1.birthday=12,31,1988;(),7.2.2 结构体变量的引用及初始化 不能将一个结构体变量作为一个整体进行输入和输出,只能对各个成员分别输入输出例如:printf(”%d,%s,%
5、c,%d,%f,%sn”,student1);()引用:student1.num=102;()成员的引用方式为:结构体变量名.成员名 注意:成员运算符.在所有运算符中优先级最高,一、结构体变量引用方法,struct clock int hour,minute,second;struct date int year,month,day;struct clock time;today,nextday;1.单独引用结构体变量的成员 today.year=2004;today.time.second=15;2.结构体变量作为一个整体引用 nextday=today;,二、结构体变量的初始化,定义时初始
6、化:将各元素初值放在“”里赋值给变量。例:struct student char name20;char sex;int age;float score;stu1,stu2=“Wangwu”,m,20,88.5;,7.3 结构体数组,结构体数组变量的定义 与结构体变量定义类似,只是结构体变量名现为结构体数组变量名如:struct student int num;char name20;char sex;int age;float score;stu30;,数组各元素在内存中连续存放,如右图所示。,结构体数组的初始化与引用,初始化:数组=初值表列;引用:结构体数组分量.结构体成员,struct
7、student int num;char name20;char sex;int age;float score;char addr30;stu3=101,”WGJ”,M,28,88.5,“CS”,102,”DYH”,F,26,88.0,”CS”,103,”DYC”,M,24,78.5,”CZ”;,结构体数组程序举例,【例】计算一个班学生的三门课程的平均成绩,并输出该班学生姓名及平均成绩。,程序:,#include#define MAXSIZE 100struct student char name16;/*学生姓名*/int grade3,average;/*三门成绩,平均分*/;,void
8、 main()int i,j,num,s;struct student stuMAXSIZE;printf(Enter number of students:);scanf(%d,7.4指针在结构体中应用,一个结构体变量的指针就是该结构体变量所占据的内存的起始地址。指针变量可存放结构体变量的指针。指针变量不仅可以用来指向结构体变量,还可以用来指向结构体数组中的元素。,7.4.1 指向结构体变量的指针,形式:struct 结构体类型名*结构体指针名 例:struct student stu1,*pst;pst=q=&stu1.num合法,【例】用指向结构体变量的指针来访问学生的各项数据。,#in
9、clude string.hstruct stuint num;char*name;char sex;float score;boy=102,Zhang ping,M,78.5,*p;,void main()p=,指向结构体数组的指针,例 输出数组中各元素中各成员的值。,struct student int num;char name20;char sex;int age;struct student stu3=10101,Zhang,M,18,10102,Li,M,19,10103,Wang,F,20;/续,main()/*续上页*/struct student*p;printf(No.Na
10、me Sex Agen);for(p=stu;pnum,p-name,p-sex,p-age);,注意事项:,如果p的初值为stu,即指向结构体数组的第1个元素stu0,则p+1指向下1个元素的起始地址stu1。区别:(+p)-num 和(p+)-nump已定义为指向struct student类型的指针变量,则p只能指向1个结构体类型数据,而不能指向结构体类型的某一成员(即p的地址不是成员的地址)。如:p=&stu.name;(错误),引例:在学校的教师和学生中填写以下表格:姓名 年龄 职业 单位;“职业”一项可分为“教师”和“学生”两类。对“单位”一项学生应填入班级编号,教师应填入某系某教
11、研室。,7.6 共用体,共用体数据类型,也是将不同数据类型的数据项,组成一个整体的构造数据类型。这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。,一、共用体类型的定义,定义一个共用体的一般形式为:union 共用体名 成员表列;其中:成员表由若干个成员组成,每个成员的形式为:类型说明符 成员名;成员名的命名应符合标识符的书写规定。例如:union perdata short class;char officae10;,把union改为struct就是结构体的定义形式,说明:与结构体声明类似,只需将struct换成union即可。与结构体一样,声明类型时不分配内存空间,只有在
12、定义其变量时才分配内存单元。共用体所占内存大小以成员中占据内存空间最多的为准。,union perdata short class;char office10;,class,office,例:#includemain()union perdata short class;char office10;a;printf(%d,sizeof(a);,又例:#includemain()struct perdata short class;char office10;a;printf(%d,sizeof(a);,比较以下两例,分析输出结果:,二、共用体变量、指针的定义,定义共用体变量与定义结构体变量相类
13、似,有以下三种方法。,1.先定义共用体,再说明共用体变量。union 共用体名 成员表列;union 共用体名 共用体变量表列;2.在定义共用体类型的同时说明共用体变量。union 共用体名 成员表列 共用体变量表列;3.直接说明共用体变量。union 成员表列 共用体变量表列;定义共用体指针与定义结构体指针相类似。如:union 共用体名*共用体指针表列;,方式一:声明共用体类型:union data short i;char ch;float f;;定义共用体变量:union data a,b,*p,c20;,方式二:声明与定义共用体:union data short i;char ch;
14、float f;a,b,*p,c20;,方式三:声明与定义共用体:union short i;char ch;float f;a,b,*p,c20;声明与定义同时进行时可以省略共用体名。,方式一:声明共用体类型:union data short i;char ch;float f;;定义共用体变量:union data a,b,*p,c20;,方式二:声明与定义共用体:union data short i;char ch;float f;a,b,*p,c20;声明与定义同时进行,方式三:声明与定义共用体:union short i;char ch;float f;a,b,*p,c20;声明与定
15、义同时进行时可以省略共用体名。,data,三、共用体变量、指针的引用,只有定义了共用体变量才能引用它。与结构体变量,只能引用共用体变量的成员,而不能整体引用共用体变量。共用体变量的引用也有三种方式。方式一:共用体变量名.成员名 方式二:共用体指针变量名-成员名 方式三:(*共用体指针变量名).成员名,例:若有共用体变量如下定义,union data int i;char ch;float f;a,b,*p,c20;p=,则可用如下方式引用:方式一:a.i,c2.i,a.ch;方式二:p-i,p-ch 方式三:(*p).i,(*p).ch,注意:不能引用共用体变量,只能引用其成员。如:a*5;是
16、非法的。可以用一个共用体变量为另一个共用体变量赋值。如:b=a;,四、共用体变量的特点,(1)在共用体类型中,同一个内存段可以用来存放几种不同类型的成员,共用体变量所占的内存单元的字节数不是所有成员的字节数之和,而是所有成员中最长字节所占内存空间的字节数。,union data short i;char ch;float f;a;,ch,i,f,例:main()union data short i;char ch;float f;a;printf(%dn,sizeof(a);/*a.i=1;a.ch=c;a.f=3.14;printf(%f,a.f);printf(addr_a=%dn,*/,
17、(2)系统采用“覆盖技术”,实现共用体变量各成员的内存共享,在某一时刻,存放的和起作用的是最后一次存入的成员值。如执行:a.i=1;a.ch=c;a.f=3.14;执行之后以上语句之后,只有3.14才是有效的成员值。因此特别要注意,当前在共用体中存放的成员值是哪一个。,(3)由于所有成员共享同一内存空间,故共用体变量与其各成员的地址相同。如:&a、&a.i、&a.ch、&a.f都是同一地址值。(4)不能对共用体变量名用常量赋值,也不能企图引用变量名来得到一个值,定义初始化共用体变量只能给出第一个成员的值。,union data int i;char ch;float f;a=2,c,3.14;
18、,a=5;m=a;,如以下这些都是非法的:,(5)可以用一个共用体变量为另一个共用体变量赋值。如:b=a;。,union data int i;char ch;float f;a=2;,以下是合法的:,例10.1 程序,void main()union exx int a,b;structint c,d;lpp;e=10;e.b=e.a+20;e.lpp.c=e.a+e.b;e.lpp.d=e.a*e.b;printf(%d,%dn,e.lpp.c,e.lpp.d);,程序执行的结果为:60,3600,e.b,e.a,10,30,60,3600,五、共用体的应用,例1:设有一个教师与学生通用的
19、表格,教师数据有姓名,年龄职业,教研室四项。学生有姓名,年龄,职业,班级四项。编程输入人员数据,再以表格输出。,#include void main()struct char name10;int age;char job;union int class;char office10;depa;body10;int n,i;,for(i=0;i10;i+)printf(input name,age,job and departmentn);scanf(%s%d%c,bodyi.name,例2:分析下面的程序,写出运行结果。#include struct a int a1;int a2;union
20、 b int b1;struct a b2;void main()union b c;c.b2.a1=2;c.b2.a2=3;c.b1=4;c.b2.a2=c.b2.a1+c.b2.a2;printf(%dn,c.b2.a2);,c,b2,a1,a2,b1,2,3,4,运行结果:7,#includemain()union data short int i2;int k;char c4;r,*s=,运行结果为:c0=9,c1=A,c2=8,c3=ak=1631076665Press any key to continue,r.c0,r.c1,r.c2,r.c3,r.i0,r.i1,r.k,例3分
21、析下面的程序,写出运行结果。,位运算与位段结构,位是指二进制数的一位,其值为0或1。位段以位为单位来定义结构体(或共用体)中成员所占存储空间的长度,含有位段的结构体类型称为位段结构。C语言和其他高级语言不同,完全支持位运算。C语言可用来代替汇编语言完成大部分编程工作,位运算便是此目的的体现之一,特别是在计算机用于检测和控制领域时需要使用位运算。,1 位运算,位运算是对字节或字中的实际二进制位进行检测、设置或移位。在用位运算符进行数的计算时,数是以补码的形式参加运算的。(1)数的补码表示 C语言中,数据占用存储空间的最小单位是字节,一个字节由8个二机制位组成。若干个字节组成一个“字”(字的位数即
22、字长,反映了计算机并行处理的最大二机制位数),字长越大,数的范围也越大,精度也越高。,最低位,最高位,补码表示数:正数的补码是它本身;负数的补码是最高位为1,其余各位(数值位)按位取反,再在最低位加1。,(2)位运算符,1)“按位与”运算符&(与AND),参加运算的两个数据,按二进制进行“与”运算。如果两个相应的二进位都为1,则该位的结果值为1,否则为0。即:0&0=0,0&1=0,1&0=0,1&1=1。如:2&5=0:2=0000000000000010 3&5=1:3=0000000000000011(&)5=0000000000000101(&)5=0000000000000101 0
23、000000000000000 0000000000000001-3&-5=-7:3=0000000000000011,“按位与”运算的常用来清零或保留某些位上的数字。将整个数如x清零只需要写成x=x&0即可。如果使数据的某一位或几位清零,只需要找到一个数,满足需要清零的相应位的位置为0,而其余位置的位为1即可。如00111111的第三位清零,保留其他位上的数字。00111111(&)11111011 00111011,2)“按位或”运算符|(或OR),参加运算的两个数据,按二进制进行“或”运算,如果两个相应的二进位只要有一个为1,则该位的结果值为1,否则为0。即:0|0=0,0|1=1,1|
24、0=1,1|1=1。按位或运算常用来指定一个数据的某些位为1。如:将0011000的低4位置为1,只需与017或运算即可。060|017:060=00110000(|)017=00001111 00111111,3)“按位异或”运算符(异或XOR)它的规则是若参加运算的两个二进位同号,则结果为0(假);异号则为1(真)。“异或”的意思是:判断两个相应的位值是否为“异”,为“异”(值不同)就取真(1),否则不为“异”(值相同)就为假(0)。即:00=0,01=1,10=1,11=0。如:5742=19:57=00111001()42=00101010 19=00010011,按位异或的应用:1)
25、使特定位翻转有01111010,想使低4位翻转,可以将它与00001111进行运算.01111010()00001111011101012)与0相,保留原值:01200=012 00001010()00000000 000010103)交换两个值,不用临时变量 a=011如 a=3,b=4.()b=100 a=ab a=111(a为7)b=ba()b=100 a=abb=011(b为3)()a=111a=100(a为4),4)“按位取反”运算符(反NOT),是一个单目运算,用来对一个二进制数按位求反即:1变0,0变1。如:025求反:025=0177752:025=00000000000101
26、01,5)“左移”运算符,使变量的每一位向左移动,移出的最高位将丢失(溢出),而右端补入0。左移的表达式形式为:变量名移动的位数 对于无符号整数,并且在不溢出的情况下,左移一位相当于乘2,左移n位相当于乘以2n。如:a=14;即00001110,a=a2;这时a为00111000,即56。,6)“右移”运算符,使变量中的每一位向右移动,移出的最低位将丢失。a如果该变量为无符号数,则高端位补0,右移后为正数。b如果该变量为有符号的正数时,则高端补0。c如果该变量为有符号的负数时,即原最高位为1,右移一位后,高端位补0或1要取决于的计算机系统:当高端补0时,称为“逻辑右移”;当高端补1时,称“算术
27、右移”。,对于Tuobo C是采用算术右移,即负数右移后高端移入1。右移表达式的形式为:变量名移动的位数 如:202=5,-202=-5。再如:a:a1:0逻辑右移)a1:1算术右移)又如:a=017,a2=3。即a为:00001111,a2为:00000011-11(原来的后两位11被舍去)右移一位相当于除2取整,右移n位相当于除以2n 取整。,7)位运算符的其他说明,位运算符与赋值运算符可以组成复合赋值运算符。如:,如果b为正数,则左侧16位补满0;如果b为负数,左端应补满1;如果b为无符号整数型,则左侧添满0。,位运算的优先级与结合性&|运算符的结合性为:&、|的为左结合性,即自左至右。
28、的为右结合性,即自右至左。,例:将一个十六进制整数(占两个字节)的各位循环左移4个二进制位,如2fe1变为fel2。解:可以这样考虑:取出十六进制整数x的最高4个二进制位到y 用:y=x(16-4)&0 xf 实现。将该整数x(占两字节)左移4个二进制位。用:x=(x4)&0 xffff 实现。将先前取出的最高4个二进制位放入低4个二进制位:用:x=x|y 实现。,程序:,#include void main()int x,y;printf(“n Input a data:”);scanf(“%x”,运行结果为:Input a data:2fe1(后按回车键)The result is fe1
29、2,2 位段结构,位段是一种特殊的结构体类型,特殊在于含有以位为单位定义存储长度的整数类型成员。计算机用于过程控制、参数检测、数据通信领域时,控制信息往往只占一个字节中的一个或几个二进位,即常常在一个字节中存放几个信息,采用常规的结构体(以字节来单位来存储)浪费存储空间。为此C语言提供了位段处理功能。,(1)位段的定义,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bit field)。利用位段能够用较少的位数存储数据,也使程序处理变得非常简单。位段定义的一般形式为:struct 位段结构体名 unsigned 位段名1:位段宽度;u
30、nsigned 位段名1:位段宽度;unsigned 位段名1:位段宽度;位段结构体变量名;,如:,定义了结构体类型struct data和两个该类型的变量data1、data2。该类型的数据由a、b、c、d四个位段成员组成,它们分别占用2、6、4、4个二进制位,共2个字节。,struct data unsigned a:2;unsigned b:6;unsigned c:4;unsigned d:4;data1,data2;,(2)位段的引用,位段引用的一般形式:位段结构体变量名.位段名 例如:data1.a=2;data2.a=data1.a;(data2.a的值为:2)data1.c=1
31、2;data2.c=data1.c+2;(data2.c的值为:14)data1.b=50;data2.c=data1.b-data1.c;(data2.c的值为:6)注意:data1.a=9;其值错误的,因为data1.a只占2位,最大值为3。这时系统自动取赋予它的数的低位。如9的二进制为1001,取其低2位为01,data1.a的值为1。,说明:,位段成员的类型必须指定为unsigned或int类型。一般使用unsigned。,struct data unsigned a:2;unsigned b:6;unsigned c:4;unsigned d:4;int e;data1,data2;
32、,一个位段成员的宽度不能大于一个字(16位)的长度。如:unsigned a:17;是非法的。位段宽度为整型常数,必须是非负的整数,范围是016,表示二进制位的个数,即表示有多少位。注意:当位段长度为16时,一般可用int来定义该数据类型。位段结构体总长度(位数),是各个位成员定义的位数之和,可以超过两个字节。位段结构体长度仍用sizeof运算符求得。如:sizeof(data1)的值为4。,位段名可省略。无名位段(只有冒号和长度)用来填充相应的机器字。,如:struct data unsigned:4;unsigned b:1;unsigned c:1;unsigned:10;data1,d
33、ata2;,这种情况只关心机器字的第5位和第6位,所以用无名位段来填充我们不关心的那些位。第14位不用,第5位和第6位要用,而第716位空间也不用。定义无名位段来占位。,位段宽度为0,表示下一位段要从下一个字开始存放。,如:struct data unsigned a:4;unsigned:0;unsigned b:3;data1,data2;,本来a、b应连续存放在一个存储单元(字。占1个字节,或2个字节)中,由于用了长度为0的位段,其作用是使下一个位段从下一个字开始存放。,一个位段必须存储在同一存储单元中,不能跨两个单元。如果第一个存储单元空间不能容纳下一个位段,则该空间不用,而从下一个单
34、元起存放该位段。,如:struct data unsigned a:2;unsigned b:5;unsigned c:6;unsigned d:4;data1,data2;,a和b在同一字节,c在一个字节,而d又在下一字节。,位段与一般变量不同,不能用&运算符获取位段地址。如:&data1.a 是非法的。因为地址是以字节为单位的,无法指向位。,位段可以在数字表达式中引用,它会被系统自动地转换成整型数。如:data1.a+5*data1.b+10/data1.c 是合法的。,在日常生活中,我们经常遇到这样一些变量,它们的取值是有限的几种。譬如:一个星期有七天,有几种基本颜色,性别有男、女,学历
35、有有限几种等。为了提高程序描述问题的直观性,ANSIC引入枚举类型解决上述数据的描述问题。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。如果一个变量只有几种可能的值,可以声明为枚举类型。,1 枚举类型的提出,7.7 枚举类型,声明枚举类型的一般形式为:enum 枚举类型名 标识符1,标识符2,.标识符n;,2 枚举类型的声明形式,例如声明:enum weekdays sun,mon,tue,wed,thu,fri,sat;enum colortype red,yellow,blue,white,black,green;enum string x1,x2,x3,x4
36、,x5,x6,;,说明:,enum是枚举类型的关键字。enum weekdays sun,mon,tue,wed,thu,fri,sat;enum weekdays为用户声明的一个枚举类型,与前面所学的结构体、共用体类似。枚举元素取值表是一些为了便于记忆而由用户自由定义的不同的标识符。在C编译中,枚举元素作为常量处理,不能加双引号。,枚举元素之间用逗号隔开(而不是分号),最后一个元素后一般不加逗号。定义时要把一个枚举类型的可能取值尽量罗列完整,并且有的类型要求顺序要符合常理(如enum weekday)。枚举类型时并不引起内存分配。只有定义变量后才分配内存单元。,2 枚举变量的定义,枚举变量的
37、定义与结构体变量类似,也有三种方式:,方式一:先声明枚举类型:enum weekdays sun,mon,tue,wed,thu,fri,sat;再定义枚举变量:enum weekdays workday;,方式二:直接定义:enum weekdays sun,mon,tue,wed,thu,fri,sat workday;,方式三:省略枚举类型名:enum sun,mon,tue,wed,thu,fri,sat workday;声明与定义同时进行时可以省略枚举类型名。,3 枚举变量的值(1)枚举变量的初始化,如果枚举变量没有初始化(即省掉“=整型常数”)时,则从枚举元素的第一个标识符开始,顺
38、次赋给标识符0、1、2、.。enum colortypered,yellow,blue,white,black,greencolor;其中:red,yellow,blue,white,black,green的值分别为:0、1、2、3、4、5。,当枚举中的某个成员赋值后,其后的成员按依次加1的规则确定其值。enum string x1,x2=0,x3,x4=50,x5,x6,x7x;此时成员值为:x1=0,x2=0,x3=1,x4=50,x5=51,x6=52,x7=53。再如:enum string x1=5,x2,x3,x4=-2,x5,x6,x7x;此时:x1=5,x2=6,x3=7,x4
39、=-2,x5=-1,x6=0,x7=1。再如:enum string x1=5,x2,x3,x4=-2x=x3;这时变量x的值为7。注意:初始化时可以赋负数,以后的标识符仍依次加1。枚举变量只能取枚举说明结构中的某个标识符常量。如:x的取值只能是x1、x2、x7当中的某一个值。,(2)枚举变量的引用,枚举变量取枚举元素中的某一个值。如:enum colortypered,yellow,blue,white,black,greencolor;当赋值:color=white;printf(“c=%dn”,color);这时输出:c=3。枚举元素可以用来作判断比较。如:enum weekdayssu
40、n,mon,tue,wed,thu,fri,satworkday=wed;可以有:if(workday=mon),if(workdaytue),if(sunsat)等。枚举值的比较规则是按其在定义时的顺序号来比较的,或则是按初始化的整型常数值来比较的。作比较运算时必须是同一类型的枚举变量。,一个整数不能直接赋给一个枚举变量,应先进行强制类型转换才能赋值。如:workday=2;是错误的。而workday=(enum weekdays)2;才是合法的,它相当于将顺序号为2的枚举元素赋给变量workday,即相当于:workday=tue;,解:设取出的球为i、j、k。要求i、j、k为5种色球之一
41、,并且它们互不相等。本题的N-S图如下(n为取法总数,pri为打印色球号,loop为3次取球标志):,例:口袋中有红、黄、蓝、白、黑5种颜色的球若干个。每次从口袋中先后取出3个球,问得到3种不同色的球的可能取法,打印出每种排列的情况。,输出一种取法的N-S图:,main()enum color red,yellow,blue,white,black;enum color i,j,k,pri;int n=0,loop;for(i=red;i=black;i+)for(j=red;j=black;j+)if(i!=j)for(k=red;k=black;k+)if(k!=i),switch(pri
42、)case red:printf(“red”);break;case yellow:printf(“yellow”);break;case blue:printf(“blue”);break;case white:printf(“white”);break;case black:printf(“black”);break;default:break;printf(“n”);printf(“ntotal:%5dn”,n);程序运行,7.8自定义数据类型,主要使用方法:如:typedef int INTEGER;typedef float REAL;表示:用INTEGER代表int类型,用REAL
43、代表float类型。这样定义:int i,j;等价于 INTEGER i,j;float a,b;等价于 REAL a,b;,声明一个新的类型别名的方法总结:(1)先按定义变量的方法写出定义体。如:int i;(2)将变量名换成新的类型别名。如:将i换成COUNT。这时上面的定义体变成:int COUNT;(3)在最前面加上typedef。如:typedef int COUNT;(4)然后可以用新的类型别名去定义变量。如:COUNT i,j,k;它等价于 int i,j,k;,7.10 链表,7.10.1 概述 链表存储结构是一种动态数据结构,其特点是它包含的数据对象的个数及其相互关系可以按需
44、要改变,存储空间是程序根据需要在程序运行过程中向系统申请获得,链表也不要求逻辑上相邻的元素在物理位置上也相邻,它没有顺序存储结构所具有的弱点。,1链表结构,(1)头指针变量head指向链表的首结点。(2)每个结点由2个域组成:1)数据域存储结点本身的信息。2)指针域指向后继结点的指针。(3)尾结点的指针域置为“NULL(空)”,作为链表结束的标志,链表结构的定义,struct studentchar name10;struct student*next;next为student类型指针变量,指向下一个结点的指针域。结点的变量或指针变量的定义:struct student node,*head;
45、node可以存放一个学生结点指针head可以存放学生结点的地址。,动态分配存储空间库函数,1void*malloc(unsigned int size);malloc在内存的动态存储区中分配一个size长度的连续存储空间。例如:int*p;p=(int*)malloc(8);p指示系统分配的4个整型存储单元的起始地址也可看成包含4个数组元素的p数组:p0,p1,p2,p3,2.void free(void*ptr);,函数free释放由指针变量ptr所指示的内存区域。例如:free(p);通过函数free将已分配的内存区域交还系统,使系统可以重新对其进行分配。,【例】动态定义数组。,#incl
46、ude void main()int n,i,*p;printf(n=);scanf(%d,程序运行结果:n=100 1 4 9 16 25 36 49 64 81,对链表的基本操作,链表的基本操作有:创建、查找、插入、删除和修改等。创建链表:从无到有地建立起一个链表。查找:按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点,则称为检索成功;否则,称为检索失败。插入:在结点ki-1与ki之间插入一个新的结点k,使表的长度增1,且逻辑关系发生如下变化:插入前,ki-1是ki的前驱,ki是ki-1的后继;插入后,新插入的结点k成为ki-1的后继、ki的前驱。,链表的删除操作,(4)删除
47、操作:删除结点ki,使链表的长度减1,且ki-1、ki和ki+1结点之间的逻辑关系发生如下变化:删除前,ki是ki+1的前驱、ki-1的后继;删除后,ki-1成为ki+1的前驱,ki+1成为ki-1的后继。,7.10.2 建立链表,1.尾插法建立单链表特点:头指针固定不变,新产生的结点总是链接到链表的尾部。操作步骤:(1)设head为链表头,last为链表尾结点,head=last=NULL;(2)生成新结点,由p指针指示,并将新结点的地址域清空:p-next=NULL;(3)如果head为NULL,则 head=p;否则 last-next=p;(4)last=p;(5)重复(2)(4),继
48、续建立新结点。,2.头插法建立单链表,特点:新产生的结点作为新的链表头插入链表。操作步骤:(1)head=NULL;(2)生成新结点,指针变量p指向该结点;(3)p-next=head;head=p;(4)重复(2)(3),继续生成下一个链表结点。,7.10.3 链表的访问,1.输出链表结点操作步骤:(1)得到链表头结点的地址head;(2)指针变量p=head;(3)输出p所指结点的成员值;(4)p后移一个结点,p=p-next;(5)重复(3)(4),直到链表为空。,2.统计链表结点的个数,一般情况下,各个单链表中结点个数是随机的,要想知道表中结点数目,必须从表头开始访问到表尾,逐个统计出
49、结点数目。3.查找链表的某个结点在链表上查找符合某个条件的结点,也必须从链表头开始访问链表。,7.10.4 链表的插入操作,在第n个结点之后插入1个新结点,插入操作步骤:(1)q指针指向新结点,i为已访问过的结点数;(2)p=head,r指向p结点的前一个结点;(3)i+,r=p,p=p-next,p结点往前移动一个结点;(4)若inext=head,head=q;(6)若inext=q,q-next=NULL;(7)否则,将q结点插入到第n个结点之后,即插入到r结点与p结点之间:r-next=q,q-next=p;(8)返回链表头head。,7.10.5 链表的删除操作,删除第n个结点(1)p=head,q指针指向p所指结点的前1个结点;(2)i为访问过的结点数目;(3)i+,q=p,p=p-next,p、q移动1个结点;(4)若p!=NULL且inext;(6)若head=NULL,链表为空,不能删除;(7)若p=NULL,第n个结点不存在,不能删除;(8)找到第n个结点,删除p结点:q-next=p-next;p的前1个结点的next值赋值为p的next域;(9)返回head。,