第十章-指针课件.ppt
《第十章-指针课件.ppt》由会员分享,可在线阅读,更多相关《第十章-指针课件.ppt(61页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、指针与指针变量的概念指针数据类型变量的指针和指向变量的指针变量数组的指针与指向数组的指针变量4指针与字符串5函数的指针与指向函数的指针变量6指针数组与指向指针的指针7小结指针-指针与指针变量的概念 导论:指针数据类型,是C语言中最具特色的数据类型。指针数据类型使得我们用户可直接对内存单元的地址进行操作,它与位运算的结合,可实现汇编语言中的低级功能,基于这个原因,把C语言称为中性语言。可以这样讲,学习C语言,如果不掌握指针数据的基本概念与应用,也就没有掌握C语言的精髓,也就是没有掌握C语言的特色。在本部分的内容中,我们将讨论指针的基本概念、指针与其它实体对象(变量、数组元素、函数)之间的间接访问
2、关系。一指针与指针变量的概念 问题的引入:我们知道,在C程序中使用最频繁的赋值操作语句,涉及到对变量的操作,亦即对内存单元的操作。如:a=20*3则意味着通过变量名a换算到其对应内存单元的地址,通过地址找到其内存单元,完成赋值操作。指针-指针与指针变量的概念 又如:对于scanf(“%d”,&a);来讲,从键盘上键入的数据送到地址为“”&a”的内存单元中。也就说,对变量a所对应内存单元的操作是通过地址进行。可见,在C语言中,对变量进行读、写操作,其实质是对内存单元进行读、写操作,而对内存单元的操作是通过地址进行的。1指针与地址 把组成内存单元首字节所对应的地址值称为该内存单元的地址,亦即内存单
3、元的指针,简称指针。指针的概念:例:short a;对于aFF7CFF7D则a变量地址FF7C亦即&aFF7C注意:对不同类型的内存单元,其编址的规则是相同的。也就是说,在32位编译系统中,内存单元的地址,即指针是用4个字节的二进制进行编码的。指针-指针与指针变量的概念记住:内存单元的地址是用4个字节的二进制进行编码,虽然指针值是整数形式,指针值的类型并非整型,而是指针型。若要将整数赋给指针变量,必须要进行强制的类型转换,即加(基类型名*)运算符。2地址值的获取 这里重要的概念是,指针值并不能由用户指定,而是通过取地址运算符“&”得到的。这样,“&变量名”为变量的地址,“&数组元素”为数组元素
4、的指针。例:double d;char ch10;则:d变量的指针:&ach4的指针:&ch43指针变量 概念:存储内存单元的地址值,也就是存放指针的变量称为指针变量。注意:在C语言中,给指针变量分配4个字节的内存单元,来存放内存单元的指针。也就是讲,指针型变量的类型长度为4。变量的指针和指向变量的指针变量 问题的引入:通过前面的讨论可得出这样的结论:变量的指针就是变量的地址,存放变量地址的变量是指针变量,用来指向某一个变量,被指向的变量称为目标变量。引入指针变量的目的,是为了实现对目标变量的间接访问。要实现这种访问目的,不失一般性,要经过以下三个步骤过程。1指针变量的定义 格式:基类型标识符
5、 *指针变量名;例:int *pa,*pb;意味着pa,pb用于存放int型变量的指针。例:double*pd1,*pd2;意味着pd1,pd2用于存放double型变量的指针。例:char*pc,c;意味着pc用于存放char型变量的指针。变量的指针和指向变量的指针变量考虑:printf(“%d,%d,%d”,sizeof(pa),sizeof(pd1),sizeof(char*);运行结果:4,4,4指针类型名记住:无论指针变量存放什么类型的指针,指针变量的长度都为4个字节。说明:在面述的指针变量定义格式中,基类型标识符是用于声明指针变量可以指向的类型,称为基类型。理解:在定义指针变量时,
6、必须约定变量是存储什么类型的指针。如对于指针变量的定义:char*pc;意味着pc变量只能存储字符型的指针,而不能存储其它类型的指针,在这里把char称为基类型。在指针变量定义语句中,指针变量前的“*”,是用来说明它所标识的变量为指针变量,而“*”本身并非变量名的组成部分。强调:基类型不同的指针变量,在32位程序中其内存单元的长度都为4个字节。变量的指针和指向变量的指针变量2指向关系的确立 引入指针变量的目的,是为了通过指针变量来访问它所指向的目标变量。要达到这个目的,必须确立指针变量与目标变量之间的指向关系。必要性:指向关系确立的途径:指向关系确立的途径,只有一种方式,即将目标变量的地址值赋
7、给指针变量。即:指针变量=目标变量的地址赋值的具体形式:实现赋值的具体形式有三种:指针变量的初始化形式;通过赋值表达式;形参与实参的结合方式。初始化形式:int a,*pa=&a;赋值表达式形式:int a,*pa;pa=&a;形参与实参结合形式:void fun(int*pa,int*pb);函数调用:fun(&a,&b);相当于:pa=&a pb=&b变量的指针和指向变量的指针变量实际上:*pa等价于*(&a)等价于a解释:这里的运算符“*”称为间接访问运算符,也称为“脱址”运算符。很显然是单目运算符,其运算对象要求为指针类型,运算结果可访问到指针所标识的内存单元。所以对指针变量的间接访问
8、运算形式,可作为左值对象,也可作为表达式的操作数及函数的参数。4指针运算 在C语言中,对指针支持以下的算术运算:指针+N,结果为:指针+N*sizeof(基类型),类型为指针值。若指针指向的内存单元是连续的,则该结果是确定的,为后移N个内存单元的地址。例若有定义:int a10;char str20;则:&a2+3的值为:&a5*(&a2+3)等价于:a5同理:*(str+3)相当于str3变量的指针和指向变量的指针变量 指针-N,结果为:指针-N*sizeof(基类型),类型为指针值。若指针指向的内存单元是连续的,则该结果是确定的,为前移N个内存单元的地址。例若有定义:char str=“a
9、bcdefg”,*ps=str+strlen(str);则:*(&str4-2)相当于*(&str2)相当于str2则:puchar(*(ps-4)的结果:输出字符d 指针-指针,结果为整数。若指针指向的内存单元是连续的,结果为两指针间的内存单元个数。例若有定义:int a10;则:printf(“%d”,&a5-&a2)的结果为:3 指针变量的+和-运算,结果为指针类型。若指向的内存单元是连续的,则意味着指针的前移或后移。例若有定义:int a=1,2,3,4,5,*pa=a;则:pa+;printf(“%d”,*pa);的结果为:2变量的指针和指向变量的指针变量例 分析下述程序。void
10、main()int*p1,*p2,x=10;float y=2.5;p1=&x;p2=&y;printf(%d,%fn,+(*p1),(*p2)+);本行有错,地址类型不匹配。加(int*)强制转换。解释为:+x与y+例 分析下述程序段。int x=10,*p;float y=2.4;x=y+;*p=x;*p+=x+y+;printf(%d,%fn,*p,y);本行出错,p无确定的指向。注意:输出结果不确定。对无确定指向指针的操作,要比对无确定值变量的操作危险得多。变量的指针和指向变量的指针变量例9.3利用指针完成两变量值的交换问题的引入:分析下列程序运行结果。#includevoid fun
11、(int a,int b)int t;t=a;a=b;b=t;void main()int x=10,y=20;fun(x,y);printf(%d,%dn,x,y);结果:10,20分析当进行函数调用时,实参变量x,y与形参变量a,b分配独立的内存单元,结合时是将实参x赋给形参a,实参y赋给形参b,函数执行时,仅完成形参变量a,b的交换,对实参变量x,y无任何影响。变量的指针和指向变量的指针变量可见,要交换实参变量的值,必须提供通过对形参变量的访问,达到改变实参变量值的途径。该途径,要通过指针的间接访问来实现。#includevoid fun(int*a,int*b)int t;t=*a;*
12、a=*b;*b=t;void main()int x=10,y=20;fun(&x,&y);printf(%d,%dn,x,y);结果:20,10指针变量a,b作函数的形参。对指针变量的间接访问实质是对其所指向目标的访问。与指针变量结合的实参,要求与基类型相同的指针值,且在结合时,确立了指针变量的指向关系。数组的指针与指向数组的指针变量 1数组的指针 数组的指针,是指数组元素对应内存单元的地址值。从更为细致的角度,将数组对应连续内存单元的起始地址值,称为数组的指针,它其实是数组中首元素的指针值。在这里,我们重点讨论一维数组、二维数组的指针表示方法。一维数组的指针 若有定义:类型说明符 数组名M
13、;则一维数组的元素指针:“数组名”表示数组的起始指针,元素“数组名i”的指针为:“&数组名i”。由于数组元素对应内存单元是连续的,则根据指针算术的原则,元素“数组名i”的指针可表示为:“数组名+i”例:int a10;则a2的指针可表示为:&a2或:a+2这样,一维数组元素的访问形式有:数组名i 直接访问*(数组名+i)间接访问例*(a+2)数组的指针与指向数组的指针变量 二维数组的指针 若有定义:类型说明符 数组名MN;则二维数组的行指针(行起始指针):“数组名”表示的是首行的行指针值;“数组名+i”表示了偏移了i*N个元素后的指针值,即第“i”行的首地址;例,若有int a34则aa+2行
14、指针另一等价的表示形式为“&数组名i”。结论:a与&a0、&a00等值;”a+1”与&a1、&a10等值;“a+2”与&a2、&a20等值。二维数组的元素“数组名ij”指针:原则:二维数组的元素指针指的是列指针在列方向上的偏移量,要表示元素指针的关键是将行指针转换为列方向上的指针值,转换方法为:在行指针左端加“*”运算符。a+1数组的指针与指向数组的指针变量所以,数组元素“数组名ij”的指针值可表示为:“i”行的行指针a+i转换为列指针*(a+i)加上列方向偏移量*(a+i)+j这样,其它等价形式为:ai+j;*a+i*N+j;*(&ai)+j 这样,二维数组的元素访问形式有:数组名ij 直接
15、访问形式间接访问形式:*(*(数组名+i)+j);*(数组名i+j);*(*数组名+i*N+j);*(*(&ai)+j)变址运算符 “”在C语言中,是变址运算符。其运算形式为:指针整数i,含义可解释为:*(指针+i)。“”运算符的优先级为最高级别,结合方向为左结合性。这样:“*(*数组名+i*N+j)”与“(*数组名)i*N+j”等价,“*(*(数组名+i)+j)”与“(*(数组名+i)j”等价。数组的指针与指向数组的指针变量2指向数组的指针变量 引入指向数组的指针变量的目的,是为了完成对数组元素的间接访问。指向数组元素的指针变量 定义格式:基类型名 *指针变量名;说明:“基类型名”要求与指向
16、数组的类型相同;指向一维数组元素的指针变量与指向二维数组元素的指针变量的定义相同。指向关系的确立:指针变量=数组元素的指针 若有定义:类型名 aM,*pa;类型名 bMN,*pb;(这里的标识符具有一般含义)。指向关系的确立:pa=a;pb=b;或pb=*b;或pb=b0;则ai与“*(pa+i)、pai”等价。bij与“*(pb+i*N+j)、pbi*N+j”等价。指向一维数组的指针变量(行指针变量)定义格式:基类型名 (*指针变量名)N;说明:“基类型”为要访问的二维数组类型,N的值与要访问的二维数组的二维大小一致。数组的指针与指向数组的指针变量注意:行指针变量与指向数组元素的指针变量虽然
17、都能完成对数组元素的间接访问,但二者有着严格的区别。引入行指针变量的目的是为了完成对二维数组元素间接访问。另外,对行指针变量值进行移时,意味着一次移过“一个一维数组”的偏移量,相当于二维数组行方向上移动。例如,对于int a43;则a+2意味着在行方向上移过二行,得到第三行的首指针值,这与行指针变量的移动类似。这样,若有定义:基类型名 aMN,(*pa)N;确立指向关系:pa=a;则aij通过pa的间接访问形式为:*(pai+j)*(*(pa+i)+j)paij 例 以下程序段的输出结果是()。int a=5,8,7,6,2,7,3,y;int*p;p=&a1;y=(*-p)+;printf(
18、%d,%d,%dn,y,*p,*p+);答案:5,8,6。(注意表达式的求值顺序)数组的指针与指向数组的指针变量数组名作函数的实参,则传递的是数组的起始地址值,则与之结合的形参必须是指向数组类型的指针变量。下面讨论数组名作函数的形参。一维数组名作函数的形参 函数定义的首部形式:类型名 函数名(类型名 数组名,)说明:一维数组名可作为函数的形参,在该形参定义中可缺省数组的大小。一维数组名作函数的形参,其形参定义:类型名 数组名,被解释为:类型名*数组名。一维数组名作函数的形参,与其结合的实参要求的是与指向数组元素的指针值。一维数组名作函数的形参,对应的实参可为二维数组元素的地址值。数组的指针与指
19、向数组的指针变量例 二分查找法的函数模块,若查找失败,则函数的返回值为-1。假设数组元素为升序。int fun(double a,int n,double key)int top,bott,loca;top=0;bott=n-1;while(top=bott)loca=(top+bott)/2;if(keyaloca)top=loca+1;else return loca;return-1;对应的调用解释:double d10;fun(d,10,12);d为数组名,为数组的起始指针,它与形参a进行结合时,将其值赋给形参a。所以,只能将double a 解释为:double*a数组的指针与指向数
20、组的指针变量例 矩阵相乘的函数模块。void mult(int*a,int*b,int*c,int m,int n,int l)int i,j,k;for(i=0;im;i+)for(j=0;jl;j+)*(c+i*l+j)=0;for(k=0;kn;k+)*(c+i*l+j)+=*(a+i*n+k)*(*(b+k*l+j);解释:int a34,b43,c33;mult(a,b,c,3,4,3);在调用时,形参a确立了与实参数组a之间指向关系,所以对ai,j元素的间接访问:*(c+i*4+j)。其它,道理相同。数组的指针与指向数组的指针变量(2)二维数组名作函数形数 函数首部的定义形式:类型
21、名 函数名(类型名 数组名N,)说明:二维数组名作函数的形参,在定义时其一维大小可以缺省,但二维大小不能缺省。二维数组名的形参定义:类型名 数组名N,被解释为:类型名(*数组名)N。二维数组名作形参,其对应的实参要求是数组的行指针值。例 分析下述程序段的运行结果。int a34=1,2,3,4,3,4,5,6,5,6,7,8;int i,(*p)4=a,*q=a0;for(i=0;i3;i+)if(i=0)(*p)i+i/2=*q+1;else p+,+q;for(i=0;i3;i+)printf(%d,aii);答案:2,4,7,数组的指针与指向数组的指针变量例9.5程序清单:#define
22、 N 3void mator(int aN)int i,j;for(i=0;iN;i+)for(j=0;ji;j+)int t=aij;aij=aji;aji=t;#includevoid main()int i,j;int aNN=1,2,3,4,5,6,7,8,9;for(i=0;iN;i+)for(j=0;jN;j+)printf(%5d,aij);printf(n);mator(a);for(i=0;iN;i+)for(j=0;jN;j+)printf(%5d,aij);printf(n);printf(n);例 N阶方阵转置到自身的函数模块。指针与字符串2习题分析 例 分析下述程序的
23、功能。#includevoid main()char*p,s80;while(strcmp(s,End)p=s;printf(input a string:);gets(s);while(*p)putchar(*p+);printf(n);答案:循环接收字符串并输出,直到输入“End”为止。(若将p=s;移出循环体外,如何?)确立指向关系输出字符串中各字符,注意指针的移动指针与字符串例 分析下述程序段的输出结果。char s=abcdefg,*p=&sstrlen(s);while(-p=s)putchar(*p);putchar(n);答案:gfedcba。(字符串的逆序输出)例 分析下列程
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第十 指针 课件
限制150内