《指针类型》PPT课件.ppt_第1页
《指针类型》PPT课件.ppt_第2页
《指针类型》PPT课件.ppt_第3页
《指针类型》PPT课件.ppt_第4页
《指针类型》PPT课件.ppt_第5页
已阅读5页,还剩135页未读 继续免费阅读

下载本文档

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

文档简介

,第10章 指针类型,10.1 指针与指针变量 10.2 指针与数组 10.3 指针与字符串 10.4 指针与结构体 10.5 指针与链表 10.6 指针与函数 10.7 指针作基类型 10.8 程序设计举例 习 题 十,10.1 指针与指针变量,10.1.1 指针变量的定义,1. 定义方法 形式: 类型标识符 *变量标识符; 定义存放指定类型数据地址的指针变量。,例如: (1) int *p1, *p2, *p3; 定义指向整型数据的指针变量p1、 p2、 p3。 (2) float *q1, *q2, *q3; 定义指向实型数据的指针变量q1、 q2、 q3。 (3) char * r1, *r2, *r3; 定义指向字符型数据的指针变量r1、 r2、 r3。,(4) struct date int year; int month; int day; *t1, *t2, *t3; 定义指向struct date类型数据的指针变量t1、 t2、 t3。,说明: (1) 指针变量可与普通变量混合定义, 指针变量的定义与普通变量的定义用变量名前加“*”区分。例如: int i, *p; /*定义整型变量i, 指针变量p*/ (2) 空指针“NULL”是一特殊的指针数据,表示空地址,相当于整型数据中的0,字符数据中的空格。 ,(3) 指针变量只能用于存放指定类型数据的地址。如以上定义的一些指针变量,p1、p2、p3只能存放整型数据的地址,q1、 q2、 q3只能存放实型数据的地址,r1、r2、r3只能存放字符型数据的地址,t1、t2、 t3只能存放struct date型数据的地址。,(4) 指针变量不能直接赋以具体地址值,不能从键盘输入值。指针变量通过间接赋以相关数据的地址,或调用存储空间分配函数得到值。例如: int i, j, k; int*p1=&i,* p2=&j,* p3=&k;/* p1得到i的地址,p2得到j的地址, p3得到k的地址*/,(5) 指针类型隐含在指针变量的定义中。例如,在上面定义指针变量p1、p2、p3时,实际上在背后隐含定义了一指向整型数据的指针类型,从形式上可以将int*看成是指向整型数据的指针类型。 与数组定义一样,通过typedef可以将指针类型与指针变量分离。例如,上面定义的指针变量p1、 p2、 p3, 可以改用如下形式: typedef int *INTPOINT; INTPOINT p1, p2, p3;,(6) 指针变量本身占有2字节的存储空间。 (7)“void *”指针类型定义的指针变量, 不指向哪一种特定类型的数据,在实际使用时通过强制类型转换成指向特定类型的数据。,2. 指针变量所指向的变量特定类型的数据,例如,对指针变量p1、p2、p3,假定已有值,*p1、 *p2、*p3代表指针变量p1、p2、p3所指向的数据,也就是p1、p2、p3的值对应的存储单元里存放的数据, 称为指针变量所指向的变量,简称指针指向变量。 如果指针变量p1、 p2、 p3分别存放整型变量i、 j、 k的地址, 则p1指向i, p2指向j,p3指向k。图10 - 1来直观反应指针变量与指针指向变量的关系。,图 10 - 1,指针指向变量*p1、*p2、*p3相当于整型变量i、j、 k。例如: int *p=&i; scanf(“%d”, p); /*等价于scanf(“%d”, &i)*/ printf(“%d”, *p); /*等价于printf(“%d”, i) */,10.1.2 指针的运算,1. 引用运算 1) 取地址运算(&) 取地址运算“&”,对指针变量进行取地址运算,可以得到指针变量本身的地址。,2) 取内容运算(*) 取内容运算“*”,前称指针运算,用于获取地址数据对应存储单元的内容。取内容运算的优先级与取地址运算优先级相同,也为第2级,结合性亦为右结合。 对指针变量,进行取内容运算可以得到指针变量所指向的数据。 取内容运算与取地址运算实质上是一对互逆运算。例如: int a, *p=&a; *(&a)就是a,&(*p)就是p; p指向a,*p与a等价。,2算术运算 指针变量可以进行有限的算术运算。 1) 加减运算 指针变量“加上”或“减去”一个整数n,相当于指针变量加上或减去n个指针所指向数据的存储单位,即指针由当前指向位置向后或向前移动n个指针所指向数据的存储单位。 加减运算常用于数组的处理。对指向一般数据的指针,加减运算无实际意义。 例如: int a10,*p=a,*x; x=p+3;/*实际上是p加上3*2个字节赋给x,x指向数组的第三个分量*/,对于不同基类型的指针,指针变量“加上”或“减去”一个整数n所移动的字节数是不同的。 例如: float a10,*p=a,*x; x=p+3;/*实际上是p加上3*4个字节赋给x,x依然指向数组的第三个分量*/,2) 自增自减运算 指针变量自增、自减运算具有上述运算的特点,但有前置后置、先用后用的考虑,务请小心。 例如: int a10, *p=a, *x; x=p+; /* x指向数组的第一个分量, p指向数组的第二个分量*/ x=+p; /* x、 p均指向数组的第二个分量*/ *p+相当于*(p+ +)。 *(p+)与(*p)+ 含义不同,前者表示地址自增,后者表示当前所指向的数据自增。,3) 指针相减 指针相减得到两指针之间数据的个数, 一般用于数组处理。,3. 关系运算 两指针的关系运算表示两指针的先后位置关系, 一般用于数组处理。除空指针外,不能进行指针与一般数值的关系运算。,10.1.3 利用指针处理简单数据,通过指向简单数据的指针变量来处理数据的步骤是: (1) 定义以相应简单数据类型为基类型的指针变量。 即定义指向简单数据的指针变量。 (2) 在指针变量与要处理的数据之间建立关联。 只需将相应数据的地址赋给指针变量。 (3) 使用指针所指向的变量来完成数据处理。,例如,要利用指针处理float数据x: (1) float *p; (2) p=&x; (3) *p即x,例 10-1 利用指针,求两个整数的和。 /*程序10 - 1,利用指针,求两个整数的和*/ main( ) int i, j; int *p, *q; /*定义指针变量*/ int sum; p=&i; q=&j; /*建立关联*/ scanf(%d, %d, p, q); sum=*p+*q; /*使用*/ printf (%d, %dn, *p, *q); printf(和=%dn, sum); ,例 10 2 指针运算示例。 /*程序10 - 2,指针运算*/ main( ) char c=a; char *p=&c; int a1, a2; int *p1, *p2; a1=100; p1=&a1; a2= (*p1)/3+7; p2=&a2; printf (a1=%d,a2=%d,*p1=%d,*p2=%dn,a1,a2,*p1, *p2); a1=(*p1)+; a2=*p2+; ,printf(a1=%d,a2=%d,*p1=%d,*p2=%dn,a1, a2, *p1, *p2); printf(%c, %cn, c, *p); 运行结果: a1=100, a2=40, *p1=100, *p2=40 a1=101, a2=40, *p1=101, *p2=随机值(p2指向a2后一个数据单元) a, a,10.1.4 指针作函数参数,例 10 3 将两个整数按从小到大的顺序输出。,先定义一个函数, 用指针变量作参数, 实现两个数的交换,然后在主函数中调用它,完成两个整数从小到大的顺序输出。,/*程序10 - 3, 将两个整数顺序输出*/ void exchang(p1, p2) /*交换两个数*/ int *p1, *p2; int p; p=*p1; *p1=*p2; *p2=p; /*结果通过*p1、 *p2带回*/ ,main( ) int a, b; int *r, *s; scanf(%d, %d, &a, &b); r=&a; s=&b; if(ab)exchang(r, s); printf(%d, %dn, a, b); 输入数据: 9, 4 运行结果: 4, 9,说明: (1) 若在函数中交换指针变量的值,则实参r、s并不改变,指针参数亦是传值。 例如: int *p; p=p1;p1=p2;p2=p; 不要希望如此能完成处理。,(2) 函数中交换值时不能使用无值的指针变量作临时变量。 例如: int *p; *p=*p1;*p1=*p2;*p2=*p; p无值,*p无意义,问题由此产生。,10.2 指针与数组,10.2.1 指向一维数组的指针变量,可以利用指向一维数组的指针变量,完成数组数据的操作处理,具体步骤如下: (1) 定义与数组相同基类型的指针变量。即定义指向数组的指针变量。 (2) 在指针变量与要处理的数组(元素)之间建立关联。只需将相应数组的首地址赋给指针变量。 (3) 使用指针所指向的变量来完成数组元素(数组)的操作处理。,例如,要利用指针处理整型数组a: (1) 定义指针变量:int *p; 。 (2) 建立关联:p=a;或p=&a0;。 p+i是下标为i的数组分量的地址。 (3) 使用 :*p即a0,*(p+i)即ai。 *p+是p当前指向的数组分量的下一个分量。 如此得到处理数组的指针法。,与指针法相类似的是处理数组的位移法,或称首地址法。 通过数组的首地址计算出下标为i的数组的元素地址(a+i), *(a+i)即ai。 指针法中p是变量,用来存放数组元素的地址。 位移法中a是常量,代表数组的首地址。,例 10-4 分别用下标法、指针法、位移法输入、输出数组元素。 方法一:,/*程序10 4 1,下标法实现数组的输入、 输出*/ main( ) int a10; int i; for (i=0; i10; i+) scanf (%d, &ai); printf(n); for (i=0; i10; i+) printf(%3d, ai); ,方法二: /*程序10 4 2, 指针法实现数组的输入、 输出*/ main( ) int a10; int i, *p; /*定义指针变量*/ p=a; /*建立关联*/ for (i=0; i10; i+) scanf (%d, p+); printf(n); for (p=a; pa+10; p+)/*使用*/ printf(%3d, *p); ,方法三: /*程序10 4 3, 位移法实现数组的输入、 输出*/ main( ) int a10; int i, ; for (i=0; i10; i+) scanf (%d, &ai); printf(n); for (i=0; i10; i+) printf(%3d, *(a+i); ,10.2.2 数组作函数参数,例 10 5 求n个整数的最大值、最小值。 求n个数的最大值的一般方法我们已非常熟悉,在这里主要考察引入指针处理数组后,数组作函数参数的应用。 假定不超过100个数,数据输入输出在主函数中完成,求最大值、最小值用一个函数完成,n个数用参数传递, 最大值、最小值使用全局变量。 ,方法一: 形参用指针, 实参用数组名。 程序如下: /*程序10 5 1, 求n个整数的最大值、 最小值*/ define L 100 int max, min; main( ) int aL; int n, i; void max-min( ); printf(); scanf(%d, &n); printf(请输入%d个数: ,n); ,for(i=0; imax) max=*(p+i); if(*(p+i)min) min=*(p+i); ,运行结果: 请输入数的个数n: 6 请输入6个数: 32 54 7 88 13 49 最大值= 88, 最小值=7,方法二: 形参用数组, 实参用指针。 程序如下: /*程序10 5 2, 求n个整数的最大值、 最小值*/ define L 100 int max, min; main( ) int aL, *p; int n, i; void max-min( ); printf(请输入数的个数n: ); scanf(%d, &n); printf(请输入%d个数: ,n); for(i=0; in; i+) scanf(%d, &ai);,p=a; max-min(p, n); /*调用函数*/ printf(最大值=%4d, 最小值=%4dn,max, min); void max-min(b, x)/*求最大值、 最小值函数*/ int b, x; int i; max=min=b0; /*最大值、 最小值初始化为第一个数据*/ for(i=1; imax) max=bi; if(bimin) min=bi; ,方法三: 形参用指针, 实参用指针。 程序如下:,/*程序10 5 3, 求n个整数的最大值、 最小值*/ define L 100 int max, min; main( ) int aL, *p; int n, i; void max-min( ); printf(请输入数的个数n: ); scanf(%d, &n); printf(请输入%d个数: ,n); for(i=0; in; i+) scanf(%d, &ai);,p=a; max-min(p, n); /*调用函数*/ printf(最大值=%4d, 最小值=%4dn,max, min); void max-min(q, x)/*求最大值、 最小值函数*/ int *q, x; int i; max=min=*q; /*最大值、 最小值初始化为第一个数据*/ for(i=1; imax) max=*(q+i); if(*(q+i)min) min=*(q+i); ,10.2.3 指向二维数组的指针变量,1. 二维数组的指针,对于二维数组,相当于一张二维表格,存储按行按列存放。 二维数组具有首地址、行地址、元素地址等相关指针。数组名代表首地址,称为二维数组的指针;行地址是二维数组中一行的首地址,二维数组中一行相当于一个一维数组;元素地址是二维数组的具体分量地址。,例如,对二维整型数组a45,相当于下面的二维数据表: 第0列 第1列 第2列 第3列 第4列 第0行:a00,a01,a02,a03,a04,相当于一维数组a0 第1行:a10,a11,a12,a13,a14,相当于一维数组a1 第2行:a20,a21,a22,a23,a24,相当于一维数组a2 第3行:a30,a31,a32,a33,a34,相当于一维数组a3,(1) a代表整个二维数组的首地址, 也就是第 0 行的首地址。也可用a0、 &a00表示。 (2) ai代表第i行的首地址。 整个二维数组也相当于一个一维数组a0、 a1、 a2、 a3, 基于一维数组的处理方法,第i行的首地址还可用*(a+i)、a+i、&ai、&ai0表示。 请注意*a表示 0 行首地址, 而非a00。 ,(3) ai+j代表aij的地址。aij的地址还可用*(a+i)+j表示。 请注意aij的地址不能用(a+i)+j表示,因为此时实际表示的是第(i+j)行的地址。 aij相对a00的绝对地址可用a0+i*5+j计算。 如果每行有m个元素,aij相对a00的绝对地址可用a0+i*m+j计算。 当然&aij是我们早就知道的aij的地址。,(4) 基于上面的分析,引入指针后,二维数组的分量aij可表示成: aij*(ai+j)*(*(a+i)+j)*(a0+i*m+j) 相应得到处理二维数组的多种形式位移法。,例10-6 输出一个指定的二维数组。 程序如下: /*程序10-6,输出一个指定的数组*/ main( ) static int a45=1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20; int i,j; for(i=0;i4;i+) for ( j=0;i5;j+) printf(“%6d“,*(a0+i*5+j); printf(“n“); ,运行结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 输出语句也可以是:printf(“%6d“,*(*(a+i)+j);,2. 指向二维数组元素的指针变量,利用指向二维数组元素的指针变量,可以完成二维数组数据的操作处理,这也就是处理二维数组的指针法。 (1) 定义与数组相同基类型的指针变量。 (2) 在指针变量与要处理的数组(元素)之间建立关联。 (3) 使用指针所指向的变量来完成数组元素(数组)的操作处理。,例 10 7 输出同例10 6指定数组。 /*程序10 7, 输出指定数组*/ main( ) static int a45=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20; int *p; for(p=a0; pa0+20; p+) if(p-a0)%5= =0) printf(n); /*每行输出5个元素*/ printf(%6d, *p); ,运行结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20,3指向整个一维数组的指针变量 一个二维数组相当于多个一维数组。通过指向整个一维数组的指针变量,也可以完成对二维数组数据的操作处理,这也是处理二维数组的指针法。 例如: int (*p)5; 定义了一个指向具有5个分量的一维数组的指针变量p,p的增值以指向的一维数组为单位,一维数组的5个分量可用(*p)0、(*p)1、(*p)2、(*p)3、(*p)4表示。 a是上面定义的数组,如果p=a,则p+i指向a数组的第i行,*(p+i)+j指向a数组的第i行第j列分量,*(*(p+i)+j)即aij。,例10-8 输出上例二维数组中某行某列分量的值。 采用指向整个一维数组的指针变量来处理。 程序如下: /*程序10-8,输出上例二维数组中某行某列分量的值*/ main( ) static int a45=1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20; int i,j; int (*p)5;/*定义指向整个一维数组的指针变量p*/ p=a;/*建立关联*/ scanf(“%d,%d“,&i,&j); printf(“a%d%d=%d“,i,j,*(*(p+i)+j);/*输出aij*/ ,输入数据:3,4 运行结果:a34=12 请注意: (1) 定义指向整个一维数组的指针变量必须用“( )”,否则定义的是指针数组,指针数组在本章10.7节中做了介绍。 (2) 指向整个一维数组的指针变量不能指向数组的元素,只能指向二维数组的行。,10.3 指针与字符串,10.3.1 字符串的指针表示,例10-9 字符串的指针表示。 main( ) char *str1; char *str2= “computer“; scanf(“%s“,str1); printf (“%s“,str1); printf (“%sn“,str2); 输入数据:HUNAN 运行结果:HUNAN computer,说明: (1) char *str= “computer“; 等价于: char *str; str= “computer“; 实际是将字符串“computer“的首地址赋给了字符类型的指针变量str。 (2) printf (“%sn“,str); 自动转换成: for (str=“computer“;*str!=0;str+) printf (“%c“,*str); (3) 可以用下标形式引用字符串中的字符,如str0表示c,str5表示t。 (4) 用指针表示字符串比用数组表示字符串更常用。,例 10 10 字符串的复制。 方法一: 字符串用字符数组表示, 字符数组用位移法处理。 程序如下: /*程序10 10 1, 字符串的复制*/ main( ) char ss =C LANGUAGE, ts20; int i; for(i=0; *(ss+i)!=0; i+) *(ts+i)=*(ss+i); *(ts+i)=0; printf(原字符串ss=%sn, ss); printf(目标字符串ts=%sn, ts); 运行结果: 原字符串ss=C LANGUAGE 目标字符串ts=C LANGUAGE,方法二: 字符串用字符指针表示。 程序如下: /*程序10 10 2, 字符串的复制*/ main( ) char ss =C LANGUAGE, ts20; char *ps, *pt; ps=ss; pt=ts; for(; *ps=0; ps+, pt+) *pt=*ps; *pt=0; printf(原字符串ss=%sn, ps); printf(目标字符串ts=%sn, pt); ,10.3.2 字符串(指针)作函数参数,例10-11 自定义求字符串长度的函数。 函数如下: int len(str) /*求字符串长度的函数*/ char str ; char *p=str; int l=0; while(*p!= 0) l+; p+; return(l); ,或直接用字符指针作函数参数, 函数如下:,int len(ps) /*求字符串长度的函数*/ char *ps; int l=0; while(*ps!=0) l+; p+; return(l); ,例10-12 用函数实现字符串的复制。 函数如下: void copy(from,to) /*字符串复制函数*/ char *from,*to; for(;*from!= 0;from+,to+) *to=*from; *to=0; ,调用时对应实参可以是字符数组,也可以是字符类型的指针。 for语句还可改写成: (1) for(;(*to=*from)!=0;from+,to+); (2) for(;(*to+=*from+)!=0;); (3) for(;(*to+=*from+);); 也可改用while语句: (1) while(*from!= 0) to+=from+; (2) while( (*to+=*from+)!=0); (3) while( *to+=*from+);,10.3.3 字符指针变量和字符数组的区别,(1) 字符数组由若干个元素组成,每个元素中存放字符串的一个字符,而字符指针变量中存放的是字符串的首地址。 (2) 初始化方式不同。对字符数组初始化要用static存储类别,在编译时进行。而对字符指针变量初始化不必加static,在实际执行时进行。 (3) 赋值方式不同。对字符数组不能整体赋值,只能转化成份量,对单个元素进行。而字符指针变量赋值可整体进行。例如: char s10; s=C+; /*错, s是常量, 怎能被赋值*/,(4) 在定义一个字符数组时,编译时即已分配内存单元,有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,但该指针变量具体指向哪个字符串,并不知道,即指针变量存放的地址不确定。例如: char s10; char *p; scanf(%s, s); /*正确*/ scanf(%s, p); /*非常危险, p的值动态*/,(5) 字符指针变量的值可以改变,字符数组名是一个常量,不能改变。例如,有简单程序: main( ) char *s=china man; s+=6; printf(%s, s); 运行结果: man,10.4 指针与结构体,10.4.1 指向结构体数据的指针变量,对使用指针来处理数据读者应有了一些体会,即先定义一以数据或元素类型为基类型的指针变量;其次在定义的指针变量与要处理的数据之间建立关联,让指针变量指向要处理的数据;然后引用指针指向变量来完成数据的处理。,例 10 13 指向结构体变量的指针变量的应用示例。 假设有一结构体,包含某人的姓名和年龄,用指向结构体变量的指针变量完成输出处理。 程序如下:,/*程序10 13, 指针应用于结构体*/ main( ) struct person char *name; int age; someone;,struct person *p; /*定义结构体类型的指针变量*/ =张三; /*假定姓名为张三*/ someone.age=20; p&someone; /*建立关联, *p即someone*/ printf(姓名=%s, 年龄=%dn,(*p).name,(*p).age); /*等价于printf(姓名=%s, 年龄=%dn,,someone.age); */ 运行结果: 姓名=张三, 年龄=20,运行结果:姓名=张三,年龄=20 说明: (1) 在用指向结构体的指针变量描述结构体的分量时必须使用“( )”。 如不使用“( )”,像上例中的“*”,由于“.”运算的优先级比“*”高,这时实际表示的是“*()”。 (2) 结构体变量的指针是指结构体变量的首地址,而不是变量中某成员的地址。指向结构体的指针变量不能指向结构体的成员。 例如: p=&;/*错误*/,(3) 引入指向结构体的指针变量后,为了书写方便和直观使用,C语言提供指向结构体成员的运算“”来得到结构体的成员。“”运算符由“”和“”复合组成,运算优先级与“.”运算相同。 例如,pname、page即、someone.age。 至此,我们有以下三种形式来引用结构体成员: 结构体变量.成员名 (*结构体指针).成员名 结构体指针成员名,例 10 14 对上例,考虑三个人组成的结构体数组的处理。程序如下:,/*程序10 14, 结构体数组的指针处理*/ struct person char *name; int age; ; struct person sp3= 张三,18,李四,19,王五, 20; main( ),struct person *p; printf( 姓名 年龄n); for (p=sp, p name, p- age ); 运行结果: 姓名 年龄 张三 18 李四 19 王五 20,10.4.2 指向结构体的指针作函数参数,例 10 15 有40个学生,每个学生包括学号、姓名及成绩,用函数输出成绩最高的学生数据。,/*程序10 15指向结构体的指针作函数参数例*/ struct student int num; char *name; float score; void print(p)/*输出函数*/ struct student *p; /*结构体指针作函数参数*/, printf (“%d %s %f n“,p num,p name,p score); int maxi(p) /*求最高分学生序号的函数*/ struct student *p; int i,t; t=0; for (i=1;i*(p+t).score) t=i; return(t); ,main( ) struct student stu40; int i,k; for (i=0;i40;i+) scanf (“%d %s %f“,&stui.num,,&stui.score); k=maxi(stu);/*结构体数组作函数参数*/ print (&stuk);/*结构体指针作函数参数*/ ,10.5 指针与链表,链表与数组不同,是一种动态地进行存储分配的数据结构,表中各元素在内存中可以不连续存放。要查找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不知道第一个元素的地址,则整个链表无法访问。故一般在链表的开头设立头指针,存放第一个元素的内存地址。这样,整个链表就可以从头到尾访问。链表的访问只能从头到尾,故是一种顺序访问,而非随机访问。 在结构体中,若只有一个指针成员域,则得到的链表为单链表;若有多个指针成员域,则得到的链表为多重链表。,10.5.1 单链表的数据描述,一般形式: struct 结构体名 成员及类型说明; struct 结构体名 *指针域; ,struct linklist int data; struct linklist *next; ; struct linklist *head;,指针域成员用于存放下一个数据的地址,由此完成链表中数据请读者注意,定义指针域成员时,结构体“struct 结构体名”的描述并没完成,这实际上形成一种递归定义的结构体类型。C语言允许在定义结构体时这样做,以完成对链表等数据结构的数据描述。,图10-2 单链表,链表中的一个数据称为一个结点。其中,head为头指针,存放链表的第一个结点地址,表示链表的开始。结点A1、A2、An的data域值a1、a2、an为整数;next域存放下一个数据的地址,即A1结点的next域存放A2结点的地址,A2结点的next域存放A3结点的地址,依此类推。最后,An结点后已无结点,其next域为空指针NULL。NULL表示链表结束。,10.5.2 单链表的建立,(1) malloc(size)在内存的动态存储区申请一个长度为size字节的连续空间。 (2) calloc(n, size) 在内存的动态存储区申请n个长度为size 字节的连续空间,函数返回值为分配空间的首地址。若此函数未被成功执行,函数返回值为0。 (3) free(p) 释放由指针p所指向的存储单元,而存储单元的大小是最近一次调用malloc( )或calloc( )函数时所申请的存储空间。,1. 头插法,例 10 16 用头插法建立一些正整数链表。,/*程序10 16,用头插法建立一些正整数链表*/ main( ) struct linklist int data; /*数据域*/ struct linklist *next; /*指针域*/ ; struct linklist *head, *p; /*head头指针, p申请单元指针*/ head=NULL; /*空链表*/,/*申请空间,并将指针强制转换成所指向的结构体类型*/ p=(struct linklist*)malloc(sizeof(struct linklist); scanf(“%d“,&pdata);/*得到数据,放结点数据域*/ while(pdata0) pnext=head;/*建立链接,当前结点指针域存放下一结点地址*/ head=p;/*用头指针保存当前结点*/ /*为下一个结点申请空间*/ p= (struct linklist*)malloc(sizeof(struct linklist); scanf(“%d“,&pdata);/*得到新结点数据*/ ,2. 尾插法,若将链表的左端固定,链表不断向右延伸,这种建立链表的方法称为尾插法。尾插法建立链表时,头指针固定不动,故必须设立一个搜索指针,向链表右边延伸,则整个算法中应设立三个链表指针,即头指针head、搜索指针p2、申请单元指针p1。尾插法最先得到的是头结点。,例10-17 用尾插法建立一些正整数链表。 /*程序10 17, 用尾插法建立一些正整数链表*/ main( ) struct linklist int data; struct linklist *next; ;,struct linklist *head, *p1, *p2; head=NULL; /*空链表*/ p1=(struct linklist*)malloc(sizeof(struct linklist); /*申请空间*/ scanf(%d, &p1-data); /*得到数据*/ while(p1-data0) if(head=NULL) head=p1; else p2-next=p1; /*建立连接*/ p2=p1; /*保存当前结点*/ /*为下一个结点申请空间*/ p1= (struct linklist*)malloc(sizeof(struct linklist); scanf(“%d“,&p1data);/*得到下一个结点数据*/ p2next=NULL;/*最后的尾结点指针域为空指针*/ ,10.5.3 单链表的基本操作,注意两点: (1) 将链表传递进函数, 只需将链表头指针传递进函数。函数的形参对应实参头指针。 (2) 对链表的访问用条件循环控制, 循环的条件是结点的指针域非空。,1. 输出链表中所有结点 void print(struct linklist *head)/*输出链表所有结点*/ struct linklist *p; p=head; /*p指向链表第一个结点*/ while(p!=NULL) printf(%d, p-data); p=p-next; /*p指向下一个结点*/ ,2. 统计链表中结点个数 只需将上述输出结点改成计数即可。 int count(struct linklist *head)/*统计链表中结点个数*/ int n=0; struct linklist *p; p=head; while(p!=NULL) n+; p=p-next; return(n); ,3. 插入操作,void ins(struct linklist *head, int i, int x)/*插入结点*/ int j; struct linklist *p, *q; p=head; j=1; while(p!=NULL)&(jnext; j+; q=(struct linklist *)malloc(sizeof(struct linklist); /*产生插入结点*/ q-data=x; q-next=p-next; /*q插入p之后 */ p-next=q; ,4. 删除操作,假设删除链表中第i个结点,先找到第i-1个结点和第i个结点,然后将第i+1个结点链接在第i-1个结点后,再释放第i个结点所占空间,完成删除操作。,void del(struct linklist *head, int i)/*删除结点*/ int j; struct linklist *p, *q; p=head; j=1; while(p!=NULL)&(jnext; j+; if(p=NULL)printf(找不到结点!); else q-next=p-next; /*删除第i个结点 */ free(p); ,双链表有两个指针域,一个指针指向左边结点,一个指针指向右边结点,用头指针表示开始结点,用尾指针表示结尾结点。例如:最简单的双链表可用如下递归结构体描述: struct linklist int data; struct linklist *llink, *rlink; ; struct linklist *head, *rear;,10.6 指针与函数,10.6.1 指向函数的指针变量,1. 定义指向函数的指针变量 形式如下: 类型标识符 (*变量标识符)( ); 类型标识符是指针变量所指向的函数类型,变量标识符是指向函数的指针变量名。 例如: int (*p)( );,说明: (1) 定义指向函数的指针变量, 可以指向一类函数。 (2) 定义指向函数的指针变量时, 括号不能省略。 例如,int *p( )定义的是指针函数头,返回值是指向整型数据的指针值,而不是指向函数的指针变量。 (3) 对指向函数的指针变量p, p+i、 p+、 p-等运算无意义。,2. 让指针变量指向函数 定义了指向函数的指针变量,就可以在指针变量与特定函数之间建立关联,让指针变量指向特定函数。 建立关联的方法为: 指针变量=函数名; 说明: (1) 指针变量只能指向定义时所指定的一类函数。 (2) 一个指针变量可以先后指向多个不同的函数。,3. 利用指针实现函数调用 指针变量一旦指向某函数,利用指针所指向的变量可以实现函数调用。 调用形式: (*指针变量)(实参表);,例 10 18 通过指针调用函数。 /*程序10 18, 通过指针调用函数,求两个数的最大值*/ float max(x, y)/*求两个数的最大值*/ float x, y; float z; z=(x=y)?x: y; return(z); main( ) float (*p)( ); /*定义指向一类实型函数的指针变量*/ float a, b; float m; scanf(%d, %d, &a, &b); p=max; /*建立关联*/ m=(*p)(a, b); /*利用指针实现函数调用*/ printf(a=%d, b=%d, max=%dn, a, b, m); ,10.6.2 指向函数的指针变量作函数参数,例 10 19 编制程序,调用一个多功能函数,对于最大值函数参数,求两个数的最大值;对于最小值函数参数,求两个数的最小值。,程序如下: /*程序10-19,指向函数的指针变量作函数参数例*/ main( ) int maxf( ),minf( ),fun( ); int a,b; int max,min; scanf(“%d,%d“,&a,&b); max= fun(a,b,maxf);/*多功能函数求最大值*/ min= fun(a,b,minf);/*多功能函数求最小值*/ printf(“最大值=%d“,max); printf(“最小值=%d“,min); ,int maxf(x,y) /*最大值函数*/ int x,y; if(xy) return(x); else return(y); int minf(x,y) /*最小值函数*/ int x,y; if(xy) return(x); else return(y); int fun(x,y,p) /*多功能函数*/ int x,y; int (*p)( );/*p参数为指向整型函数的指针变量*/ int result; result=(*p)(x,y);/*通过指针调用函数*/ return(result); ,输入数据:28,32 运行结果: 最大值=32 最小值=28 第一次调用fun( )函数时,除了将a、b的值传递给x、y外,还将函数maxf( )的入口地址(maxf)传递给指向函数的指针变量p,这时函数fun( )中的(*p)(x, y)相当于maxf(x, y)。 第二次调用fun( )函数时,a、b的值同样传递给x、y,另将函数minf( )的入口地址(minf)传递给指向函数的指针变量p,这时函数fun( )中的(*p)(x,y)相当于minf(x,y)。,10.6.3 指针函数,例 10 20 设有若干学生,每个学生有6门课程成绩。输入学生序号,输出其全部成绩,用指针函数实现。,程序如下: /*程序10-20,指针函数示例*/ float *pointf(p,n) /*计算第n个学生的成绩数据地址的指针函数*/ float (*p)6;/*指向一个学生整个成绩的指针变量*/ int n; float *t; t=*(p+n); return(t); main( ), static float score6=70,85,78,80,90,99,90,79,63,70,56,68,49,60,56,50,70,60,60,

温馨提示

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

评论

0/150

提交评论