C教案-Ch8.doc_第1页
C教案-Ch8.doc_第2页
C教案-Ch8.doc_第3页
C教案-Ch8.doc_第4页
C教案-Ch8.doc_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

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

文档简介

第八章 指针 指针的优点和缺点 一优点: 1. 使程序简洁、紧凑、高效2. 有效地表示复杂的数据结构3. 动态分配内存4. 得到多于一个的函数返回值用指针可以直接访问内存单元中的数据,有时用指针可以写出更紧凑和更有效的程序代码,指针支持内存的动态分配,指针还能有效地处理诸如链表、树、图等复杂的数据结构。所以,指针是C的最强特性。二缺点:指针既是C的最强特性,也是C的最危险特性,指针使用不当,很容易指到意想不到的地方,而且很容易用错,产生的错误也不易发现。因此,人们常把指针和goto归于一类。 本章重点与难点:理解指针的概念、学会如何用指针来访问变量和数组,如何用指针作为函数参数,处理一些其它数据类型无法解决的问题,以及指针和字符串、指针和函数之间的关系等。8.1 指针的概念一. 变量与地址在计算机中,内存是一个连续编号或编址的空间。也就是说,每一个存储单元(在微型计算机中通常是一个字节)都有一个固定的编号,就像门牌号码一样,这个编号称为地址。不同的数据类型占用不同字节的存储空间,而每一字节都有一个地址,一般把每个数据的首字节地址称为该数据的地址。 例如,我们在程序中进行了如下的定义: int x; float k; 编译系统(或函数调用时)会根据整个程序的情况,为i和k分别分配2字节和4字节的存储空间(如图所示),i的地址是2000,k的地址是2002。(注意,变量的地址分配情况取决于当前计算机内存状况和程序状况,不是固定不变的,图中的地址值仅作参考)。 2000 x 2002 k 地址 变量 二. 指针与指针变量 1指针:一个变量的地址。 2指针变量:专门存放变量地址的变量叫指针变量。 指针 2000 整型变量 i 变量的内容 10 变量的地址 变量地址(指针) 变量值 2002 指针变量 地址存入 指向 指针变量 2004 变量 i_pointer 2000 变量指针变量 三运算符 &与 *1 含义:&: 含义: 取变量的地址, 单目运算符, 优先级: 2, 结合性:自右向左*: 含义: 取指针所指向变量的内容 单目运算符, 优先级: 2, 结合性:自右向左2. 两者关系: 互为逆运算 (图) 如果i=10, &i=2000, i_pointer=&i, i_pointer - 指针变量,它的内容是地址量(2000) *i_pointer - 指针的目标变量,它的内容是数据(10)i_pointer = &i = &(*i_pointer) i = *i_pointer = *(&i)四. 直接访问与间接访问 直接访问:按变量名(地址)访问该变量 间接访问:通过存放变量地址的指针变量去访问该变量例1: i=3; -直接访问 (图)例2: *i_pointer=20; -间接访问 (图) 例3: k = * i_pointer;-间接访问 (图)8.2 指针变量一. 指针变量的定义1. 一般形式: 数据类型 *指针变量名;其中:数据类型:指针的目标变量的数据类型* :表示定义指针变量,不是“*”运算符指针变量名:合法标识符如:int *p1, *p2 ; float *q ;char *name ;2注意问题: int *p1, *p2; 与 int p1, p2; 指针变量名是p1、p2 ,不是 *p1、*p2 指针变量只能指向定义时所规定类型的变量 指针变量定义后,变量值不确定,应用前必须先赋值二. 指针变量的初始化一般形式: 数据类型 *指针变量名 = 初始地址值; (赋给指针变量,不是赋给目标变量)如:int i; int *p=&i; 变量必须与已说明过的类型应一致 int *p=&i; int i; 必须用有效的地址作初值(比如已说明过的变量的地址)int i; int *p = &i; int *q = p; 可以用已初始化指针变量作初值例8-1:指针的概念main() int a; int *pa=&a; a=10; printf(a:%dn,a); printf(*pa:%dn,*pa); (图) printf(&a:%xn,&a);printf(pa:%xn,pa); printf(&pa:%xn,&pa);运行结果:(执行过程图见ch5:P14)a:10*pa:10&a:f86pa:f86&pa:f88例8-2:输入两个数,并使其从大到小输出main() int *p1,*p2,*p,a,b; scanf(“%d,%d”,&a,&b); p1=&a; p2=&b; if(ab) p=p1; p1=p2; p2=p; printf(“a=%d,b=%dn”,a,b); (图) printf(max=%dn”, *p1); printf( “min=%dn, *p2); 运行结果: (执行过程图见ch5:P15)a=5,b=9 max=9,min=5三. 指针变量作为函数参数( 特点:共享内存, “双向”传递)例8-3:将数从大到小输出(1)swap(int x,int y) int temp; temp=x;x=y;y=temp;main() int a,b; scanf(%d,%d,&a,&b); if(ab) swap(a,b); printf(n%d,%dn,a,b);运行结果:5, 9(2)swap(int *p1, int *p2) int p; p=*p1; *p1=*p2; *p2=p;main() int a,b; int *pointer_1,*pointer_2; scanf(%d,%d,&a,&b); pointer_1=&a; pointer_2=&b; if(ab) swap(pointer_1,pointer_2); printf(n%d,%dn,a,b);运行结果:9,5 (3)swap(int *p1, int *p2) int *p; *p=*p1; *p1=*p2; *p2=*p;main() int a,b; int *pointer_1,*pointer_2; scanf(%d,%d,&a,&b); pointer_1=&a; pointer_2=&b; if(ab) swap(pointer_1,pointer_2); printf(n%d,%dn,a,b);结果:程序错误!分析:指针变量在使用前必须赋值! (4) swap(int x,int y) int t; t=x; x=y; y=t;main() int a,b; int *pointer_1,*pointer_2; scanf(%d,%d,&a,&b); pointer_1=&a; pointer_2=&b; if(ab) swap(*pointer_1,*pointer_2); printf(n%d,%dn,a,b);运行结果:5,9 (5) swap(int *p1, int *p2) int *p; p=p1; p1=p2; p2=p; main() int a,b; int *pointer_1,*pointer_2; scanf(%d,%d,&a,&b); pointer_1=&a; pointer_2=&b; if(ab) swap(pointer_1,pointer_2); printf(%d,*pointer_1); printf(%d,*pointer_2); 运行结果:5,9 8.3 指针与数组一. 指向数组元素的指针变量如: int a10; int *p; p=&a0; / p=a; (图)或: int *p=&a0;或: int *p=a;数组名是表示数组首地址的地址常量二. 指针的运算1. 指针变量的赋值运算:l p=&a; (将变量a地址p)l p=array; (将数组array首地址p)l p=&arrayi; (将数组元素地址p)l p1=p2; (指针变量p2值p1)l不能把一个整数p,也不能把p的值整型变量如: int i, *p; p=1000; ()i=p; ()2. 指针的算术运算: pi pid (i为整型数,d为p指向的变量所占字节数) p+, p-, p+i, p-i, p+=i, p-=i等 若p1与p2指向同一数组,p1-p2=两指针间元素个数p(p1-p2)/d p1+p2 无意义如: p指向float数,则:p+1 p+14如: p指向int型数组,且 p=&a0;则:p+1 指向a1如:int a10; int *p=&a2; (图) p+;*p=1;如:int a10; int *p1=&a2; int *p2=&a5;则:p2-p1=3;3. 指针变量的关系运算: 若p1和p2指向同一数组,则 p1p2 表示p1指的元素在后 p1=p2 表示p1与p2指向同一元素 若p1与p2不指向同一数组,比较无意义 p=NULL或p!=NULL三. 数组元素表示方法 (图) 例8-4:数组元素的引用方法main() int a5,*pa,i; for(i=0;i5;i+) ai=i+1; pa=a; for(i=0;i5;i+) printf(*(pa+%d):%dn,i,*(pa+i); (图) for(i=0;i5;i+) printf(*(a+%d):%dn,i,*(a+i); for(i=0;i5;i+) printf(pa%d:%dn,i,pai); for(i=0;i5;i+) printf(a%d:%dn,i,ai);例8-5:注意指针变量的运算void main() int a =5,8,7,6,2,7,3; int y,*p=&a1; y=(*-p)+; printf(“%d ”,y); (图) printf(“%d”,a0); 例8-6:注意指针的当前值main() int i,*p,a7; p=a; for(i=0;i7;i+) scanf(%d,p+); printf(n); p=a; for(i=0;i7;i+,p+) printf(%d,*p);四. 数组名作函数参数1. 数组名作函数参数,是地址传递2. 数组名作函数参数,实参与形参的对应关系 表 8-1实参形参数组名数组名数组名指针变量指针变量数组名指针变量指针变量例8-7:将数组a中的n个整数按相反顺序存放 (1)void inv(int x, int n) 形参是数组名 int t,i,j,m=(n-1)/2; for(i=0;i=m;i+) j=n-1-i; t=xi; xi=xj; xj=t; main() int i,a10=3,7,9,11,0,6,7,5,4,2;实参也是数组名 inv(a,10); printf(The reverted array is :n); for(i=0;i10;i+) printf(%d,ai); printf(n);(2)void inv(int *x, int n)形参是指针变量 int t,*p,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i=p;i+,j-) t=*i; *i=*j; *j=t; main() int i,a10=3,7,9,11,0,6,7,5,4,2;实参是数组名 inv(a,10); printf(The reverted array is:n);for(i=0;i10;i+) printf(%d,ai); printf(n);(3)void inv(int *x, int n)形参是指针变量 int t,*i,*j,*p,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i=p;i+,j-) t=*i; *i=*j; *j=t; main()实参是也指针变量 int i,a10,*p=a;for(i=0;i10;i+,p+) scanf(%d,p); p=a; inv(p,10); printf(The array has been reverted:n); for(p=a;pa+10;p+) printf(%d,*p);表 8-2变量名作为函数参数与数组名作为函数参数的比较:实参的类型变量名 数组名 形参的类型变量名数组名或指针变量 传递的信息变量的值实参数组首元素的地址通过函数调用能 否改变实参的值 不能 能 一级指针变量与一维数组的关系int *p 与 int q10 数组名是指针(地址)常量 p=q; p+i 是qi的地址 数组元素的表示方法: 下标法和指针法即:若 p=q 则:piqi*(p+i)*(q+i) 形参数组实质上是指针变量, 即: int q int *q 在定义指针变量(不是形参)时,不能把int *p 写成int p; 系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配2*10字节的内存区五. 指针与二维数组1. 二维数组的地址 对于一维数组:(1)数组名array表示数组的首地址,即array0的地址;(2)数组名array是地址常量 (3)array+i是元素arrayi的地址(4)arrayi*(array+i) 对于二维数组: int a34; (1) a是数组名, 包含三个元素: a0,a1,a2,即: 第0行元素,第1行元素,第2行元素, a是该一维数组的数组名, 所以它是其首元素的地址,即第0行的地址, a+1,a+2分别是第1行和第2行的地址,即: a+0=&a0, a+1=&a1, a+2=&a3, 所以, ai=*(a+i) (2) 每个元素ai, 又是一个一维数组, 它包含4个元素: ai0, ai1, ai2, ai3, 即第i 行的4个列元素, ai是这4个列元素的数组名, 所以它是其首元素的地址, 即: 第i行第0列的地址,则ai+1, ai+2, ai+3, 分别是第i 行第1列,第2列,第3列的地址, 即: ai+ j = &aij, 所以aij = *(ai+j ) = *(*(a+i )+j 2. 注意问题: a-二维数组的首地址,即第0行的首地址 a+i-第 i 行的首地址 ai*(a+i)- 第 i 行第 0 列的元素地址 ai+j*(a+i)+j -第 i 行、第 j 列的元素地址 *(ai+j)*(*(a+i)+j)aij a+i=&ai=ai=*(a+i)=&ai0 值相等,含义不同 a+i&ai,表示第i行首地址,指向行 ai*(a+i)&ai0,表示第i行、第0列元素地址,指向列地址表示:(1) a+1 行指针(2) &a10(3) a1(4) *(a+1) 列指针(5) (int *) (a+1) 200020022004200620082010201220142016201820202022 a34a00a01a02a03a10二维数组元素表示形式:(1)a12(2)*(a1+2)(3)*(*(a+1)+2)(4)*(&a00+1*4+2)地址表示:(1) &a12(2) a1+2(3) *(a+1)+2(4)&a00+1*4+2a11a12a13a20a21a22a23表 8-3表示形式含义地址a二维数组名,数组首地址2000a0, *(a+0), *a第0行第0列元素地址2000a+1第1行首地址2008a1, *(a+1)第1行第0列元素地址2008a1+2, *(a+1)+2, &a12第1行第2列元素地址2012*(a1+2), *(*(a+1)+2), a12第1行第2列元素值13 (元素值为13)3. 二维数组的指针变量 指向二维数组元素的指针变量例8-8: 指向二维数组元素的指针变量main() int a34= 1,3,5,7,9,11,13,15,17,19,21,23 ; int *p; for(p=a0;pa0+12;p+) if(p-a0)%4=0) printf(n);printf(%4d ,*p); P a34a00a01a02a03a10a11a12p=*a; p=&a00; p=(int *)a; p=a; a13a20a21a22a23 指向一维数组元素的指针变量 定义形式:数据类型 (*指针名)一维数组维数;如: int (*p)4;( )不能少,int (*p)4与int *p4不同一维数组指针变量维数和二维数组列数必须相同 可让p指向二维数组某一行p的值是一维数组的首地址,p是行指针如:int a34, (*p)4=a;P a a34p0+1 或 *p+1a00*(*p+1) 或 (*p)1a01a02P+1a+1 a03a10p1+2 或 *(p+1)+2a11*(*(p+1)+2)a12P+2a+2 a13a20a21a22a23例8-9: 一维数组指针变量举例main() static int a34=1,3,5,7,9,11,13,15,17,19,21,23;p=a0; p=*a; p=&a00; p=&a0; int i,j,(*p)4; for(p=a,i=0;i3;i+,p+) for(j=0;j4;j+) printf(%d ,*(*p+j); printf(n);4. 二维数组的指针作函数参数用指向变量的指针变量用指向一维数组的指针变量用二维数组名若 int a34; int (*p1)4=a; int *p2=a0; 实参和形参的情况如下表: 表 8-4实参 形参数组名a数组名int x4数组名a 指针变量int (*q)4指针变量p1数组名int x4指针变量p1指针变量int (*q)4 指针变量p2指针变量int *q例8-10: 3个学生各学4门课, 计算总平均分, 并输出第n个学生成绩函数声明 main() void average(float *p, int n); void search(float (*p)4, int n);列指针 float score34=65,67,79,60, 80,87,90,81, 90,99,100,98; average(*score,12);行指针 search(score,2);void average(float *p,int n) float *p_end, sum=0,aver; p_end=p+n-1; for(;p=p_end;p+) sum=sum+(*p);float p4 aver=sum/n; printf(average=%5.2fn,aver);void search(float (*p)4, int n)pni int i; printf( No.%d :n,n); for(i=0;i4;i+) printf(%5.2f , *(*(p+n)+i);例8-11: 3个学生各学4门课,计算总平均分,并查找一门以上课程不及格的学生, 输出其各门课成绩void search(float (*p)4, int n) int i,j,flag;pni for(j=0;jn;j+) flag=0; for(i=0;i4;i+) if(*(*(p+j)+i)60) flag=1; if(flag=1) printf(No.%d is fail,his scores are:n,j+1); for(i=0;iy) z=x; else z=y; return(z);三.用函数指针变量作函数参数例8-16:用函数指针变量作参数,求最大值、最小值和两数之和三.void main() int a,b,max(int,int),min(int,int),add(int,int); void process(int,int,int (*fun)(); scanf(%d,%d,&a,&b); process(a,b,max); process(a,b,min); process(a,b,add);void process(int x,int y,int (*fun)() int result; result=(*fun)(x,y); printf(%dn,result);max(int x,int y) printf(“max=”); return(xy?x:y);min(int x,int y) printf(“min=”); return(xy?x:y);add(int x,int y) printf(“sum=”); return(x+y);8.6 返回指针值的函数 函数定义形式: 类型标识符 * 函数名(参数表); 如:int *f(int x, int y);此函数是指针型函数即返回值是指针 返回的指针指向的数据类型例8-17:指针函数实现:有若干学生成绩,要求输入学生序号后,能输出其全部成绩main() float score4=60,70,80,90,56,89,67,88,34,78,90,66; float *search(float (*pointer)4,int n), *p; int i,m; printf(Enter the number of student:); scanf(%d,&m); printf(The scores of No.%d are:n,m); p=search(score,m); for(i=0;iy) return

温馨提示

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

评论

0/150

提交评论