指针与指针变量



《指针与指针变量》由会员分享,可在线阅读,更多相关《指针与指针变量(94页珍藏版)》请在装配图网上搜索。
1、单击此处编辑母版标题样式,,单击此处编辑母版文本样式,,第二级,,第三级,,第四级,,第五级,,*,C,语言程序设计教程,*,第8章 指针,,8.1 指针与指针变量,,8.2 指针与函数,,8.3 指针与数组,,8.4 指针与字符串,,8.5 指针数组与命令行参数,,8.6 程序举例,第 8 章 指针,C,语言程序设计教程,10/3/2024,1,,C,语言程序设计教程,8.1 指针与指针变量,8.1.1 指针的概念,,1.内存与变量地址,,内存地址:,内存是计算机用于存储数据的存储器,以一个字节作为存储单元,为了便于访问,给每个字节单元一个唯一的编号,第一字节单元编号为0,以后各单元按顺序
2、连续编号,这些单元编号称为内存单元的地址 。,,变量地址:,变量所分配存储空间的首字节单元地址(字节单元编号),。,10/3/2024,2,,C,语言程序设计教程,2. 变量的三要素:,名字、类型与值,,每个变量都通过,变量名与相应的存储单元相连系,,具体分配哪些单元给变量,由C编译系统完成变量名到对应内存单元地址的变换。,,,变量分配存储空间的,大小,由,类型,决定。,,变量的值,则是指相应,存储单元的内容,。,,,3.,内存存取方式,,直接存取,:把直接按变量名或地址存取变量值的方式称为 “直接存取”方式。,,间接存取,:通过定义一种特殊的变量专门存放内存或变量的地址,然后根据该地址值再去
3、访问相应的存储单元,。,10/3/2024,3,,C,语言程序设计教程,系统为特殊变量,p(,用来存放地址的)分配的存储空间地址是4800,,p,中保存的是变量,a,的地址,即4000,当要读取,a,变量的值12345时,不是直接通过,a,变量,也不是直接通过保存12345的内存单元的地址4000去取值,而是先通过变量,p,得到,p,的值4000,即,a,的地址,再根据地址4000读取它所指向单元的值12345。,这种间接的通过变量,p,得到变量,a,的地址,再存取变量,a,的值的方式即为“间接存取”。,,,通常称变量,p,指向变量,a,,变量,a,是变量,p,所指向的对象,…,4000,12
4、345,4000,,4002,4800,p,a,p(4800),,p(4800),,a(4000),,4000,12345,4000,间接存取示意图,10/3/2024,4,,C,语言程序设计教程,4.指针的概念,在C语言中,用,指针,来表示一个变量指向另一个变量这样的指向关系。,,所谓指针即地址。,,一个变量的指针即该变量的地址,如4000就是指向变量,a,的指针。,,,指针变量,:专门存放地址的变量,如,p,即是一个指针变量,它存放的,是,a,的地址4000。,10/3/2024,5,,C,语言程序设计教程,8.1.2 指针变量的定义与初始化,,1. 指针变量的定义,,,类型标识符
5、*指针变量名;,,例:,float *p1;,(,定义,p1,为,指向实型变量的指针变量,),,,char *p2;,(,定义,p2,为,指向字符型变量的指针变量,),,在指针变量定义中,*是一个说明符,它表明其后的变量是指针变量,如,p,是指针变量,而不要认为“*,p”,是指针变量。,,指针变量定义时指定的数据类型不是指针变量本身(变量存放的值)的数据类型,而是指针变量所指向的对象(或称目标)的数据类型,,,指针变量存放的是所指向的某个变量的地址值,而普通变量保存的是该变量本身的值,,,指针变量并不固定指向一个变量,可指向同类型的不同变量,10/3/2024,6,,C,语言程序设计教程,
6、(1),指针运算符与地址运算符,,,与指针引用有关的两个运算符:&与*。,,,&:取地址运算符,,,,*:指针运算符,或称指向运算符、间接访问运算 符。,,指针指向的对象的表示形式:,,*指针变量,,此处*是访问指针所指对象的运算符,与指针定义时的*不同。,2. 指针变量初始化,,10/3/2024,7,,C,语言程序设计教程,(,2) 指针变量初始化,若有定义:,,,int,a,*p;,,语句仅仅定义了指针变量,p,,但指针变量并未指向确定的变量(或内存单元)。因为这些指针变量还没有赋给确定的地址值,只有将某一具体变量的地址赋给指针变量之后,指针变量才指向确定的变量(内存单元)。,,指针变
7、量初始化:,在定义指针时同时给指针一个初始值,,如:,int,a,*p=,4000,3,a(4000),pa,*pa,10/3/2024,8,,C,语言程序设计教程,(3) 指针变量的引用,,① *指针变量名——代表所指变量的值。,,,② 指针变量名——代表所指变量的地址。,,有定义:,int,a,*p=,,用*,p,来表示,p,指向的对象,a,*p,与,a,是等价的。,,*,p,可以象普通变量一样使用。 例如:,,,a=12;,,*p=12;,,,scanf,("%d",,scanf,("%d",p);,,,printf,(,“,%d%d,”,,*p,a);,,注意,:,*,与,&
8、,具有相同的优先级,,结合方向从右到左,。这样,,&*,p,即,&(*,p),,是对变量,*,p,取地址,它与,&,a,等价;,p,与,&(*,p),等价,,a,与,*(&,a),等价。,,10/3/2024,9,,C,语言程序设计教程,例,,,main(0,,{,int,a=100,b=10,*p1,p2;,,p1=,,printf,(,“,%d,%d,%d,%d\n,”,,a,b,*p1,*p2);,,},10/3/2024,10,,C,语言程序设计教程,,例 输入,a,b,两个整数,按从大到小顺序输出。,,main(),,{,int,*p1,*p2,*p,a,b;,,scanf,(,“
9、,%d,%d,”,,,,p1=,,if(a
10、在,a,可以出现的任何位置.,,,*,与&的说明:设,int,a=1,*p;p=,,①&*p,,,从左向右结合,相当于&,a,,②*&a,,,先取,a,的地址,再进行*运算,即指向&,a,所指向的变量,相当于,a,,③(*p)++,,,相当于,a++,10/3/2024,12,,C,语言程序设计教程,,例 从键盘输入三个整数,要求设三个指针变量,p1,p2,p3,,使其分别从大到小指向三个整数,然后输出。,,main(),,{,int,*p1,*p2,*p3,i,j,k,temp;,,scanf,(,“,%d,%d,%d,”,,,,p1=,,if(_____ ){temp=*p1;______
11、__;__________;},,if(_____){temp=*p1;________;_________;},,if(_ ___){temp=*p2;_________;_________;},,printf,(,“,%d%d%d,”,,*p1,*p2,*p3);,,},10/3/2024,13,,C,语言程序设计教程,8.1.3 指针运算,1. 指针的赋值运算,,(1)将变量地址值赋给指针变量,使指针指向该变量。,,设有如下定义:,,,int,a,b,*pa,*,pb,;,,,float *pf;,,第一行定义了整型变量,a,b,及指针变量,pa,,pb,。pa、,pb,还没有被赋值,
12、因此,pa、,pb,没有指向任何变量, 下面语句完成对,pa,,pb,的赋值:,,,pa=,,pb,=,,10/3/2024,14,,C,语言程序设计教程,例如,:,,int,j,k;,,,int,*pointer1,*pointer2;,,,pointer1=,,pointer2=,pointer1,j,pointer2,k,10/3/2024,15,,C,语言程序设计教程,(2) 相同类型的指针变量间的赋值,,pa,与,pb,都是整型指针变量,它们间可以相互赋值,如:,pb,=pa;,即,pa,,pb,都指向变量,a,,此时,a、*pa、*,pb,是等价的。指针指向变化如下图:,注意,:只
13、有相同类型的指针变量才能相互赋值,如,pf=pa;,是不允许的。因为,pa,是整型指针,,pf,是浮点型指针。,&a,&b,pa,pb,a,*pa,b,*,pb,&a,&a,pa,pb,a,*pa,*,pb,b,10/3/2024,16,,C,语言程序设计教程,(3),给指针变量赋,空值,给指针变量赋,空值,,说明该指针不指向任何变量。,,“空”指针值用,NULL,表示,,NULL,是在头文件,stdio,.h,中预定义的常量,其值为0,在使用时应加上预定义行,如:,,#,include ",stdio,.h",,,int,*pa=NULL;,,,,亦可以用下面的语句给指针赋“空值”:,,,,
14、a=0;,,,或:,pa=,’,\0,’,;,,,这里指针,pa,并非指向0地址单元,而是具有一个确定的“空值”,表示,pa,不指向任何变量。,,注意,:,指针虽然可以赋值0,但却不能把其它的常量地址赋给指针。例如:,pa=4000;,是非法的,。,10/3/2024,17,,C,语言程序设计教程,例 8.1 指针定义与初始化,main(),,{,int,a,b;,,int,*pointer_1,*pointer_2;,,a=100;b=10;,,pointer_1=,,pointer_2=,,,printf,("%d,%d\n",a,b);,,printf,("%d,%d\n",*poin
15、ter_1,*pointer_2);,,},10/3/2024,18,,C,语言程序设计教程,程序运行结果:,,100,10,,100,10,&a,&b,b,Pointer_1,Pointer_2,a,*pointer_1,*pointer_2,10/3/2024,19,,C,语言程序设计教程,例8.2 从键盘上输入两个整数到,a、b,,按由大到小输出。,#,include <,stdio,.h>,,main( ),,{,int,a,b,*pa=&a,*,pb,=/*,定义指针变量,pa、,pb,,,如下页图,a*/,,,scanf,(″%d%d″,,,if (*pa<*,pb,) { p=
16、pa; /*,进行指针交换,如下页,图,b,c*/,,pa=,pb,;,,,pb,=p;,,},,printf,(″\n a=%d,b=%d\n″,a,b);,,printf,(″\n max=%d,min=%d″,*pa,*,pb,);,,/* pa,指向大数,,pb,指向小数*/,,},10/3/2024,20,,C,语言程序设计教程,若输入:,12 22↙,输出结果:,a=12,b=22 max=22,min=12,(,b),,(c),,指针变化示意图,12,,,,22,p,,pa,,pb,12,,,22,p,,pa,,pb,,
17、pa,,pb,a,b,10/3/2024,21,,C,语言程序设计教程,2. 指针的算术运算,(1) 加减运算,:,一个指针可以加、减一个整数,n,,其结果与指针所指对象的数据类型有关。指针变量的值应增加或减少“,n×,sizeof,(,指针类型)”。,,,加减运算常用于数组的处理,。,对指向一般数据的指针,加减运算无实际意义。例如: ,,,int,a[10],*p=a,*x; ,,x=p+3; /*,实际上是,p,加上3*2个字节赋给,x, x,指向数组的第三个分量*/,,对于不同基类型的指针,指针变量,“,加上,”,或,“,减去,”,一个整数,n,所移动的字节数是不同的。例如: ,,
18、,float a[10], *p=a, *x; ,,p=p+3; /*,实际上是,p,加上3*4个字节赋给,x, x,依然指向数组的第三个分量*/,10/3/2024,22,,C,语言程序设计教程,(2) 自增自减运算,指针变量自增、自减运算具有上述运算的特点,但有前置后置、先用后用的考虑,务请小心。 例如: ,,,int,a[10], *p=a, *x; ,,x=p++; /* x,第一个元素分量,,p,指向第二个元素*/,x=++p; /* x、 p,均指向数组的第二个分量*/,,*,,p++,相当于*,(,p+ +)。,,*(p++),与(*,p)++,含义不同,前者表示,
19、地址自增,,后者表示,当前,所指向的数据自增,。,10/3/2024,23,,C,语言程序设计教程,2.,*&,a,的含意是什么?,,(答:,a,),,3.,(*p)++,相当于什么?,,(答:,a++,),思考:,,1.若有定义,int,a,*p;,,执行了,“,p=&a”,,则: “&*,p”,的含意是什,么?,(答:,相当于&,a,),10/3/2024,24,,C,语言程序设计教程,3.,指针的关系运算,,与基本类型变量一样,指针可以进行关系运算。,,在关系表达式中允许对两个指针进行所有的关系运算。若,p,q,是两个同类型的指针变量,则:,p>q,p=q,都是允许的。,,指针的关系运
20、算在指向数组的指针中广泛的运用,假设,p、q,是指向同一数组的两个指针,执行,p>q,的运算,其含义为,若表达式结果为真(非0值),则说明,p,所指元素在,q,所指元素之后。或者说,q,所指元素离数组第一个元素更近些。,,,注意:在指针进行关系运算之前,指针必须指向确定的变量或存储区域,即指针有初始值;另外,只有相同类型的指针才能进行比较。,,10/3/2024,25,,C,语言程序设计教程,8.1.4 多级,指针,,把指向指针型数据的指针变量称为指向指针的指针,或,称多级指针,。,,二级指针的定义形式如下:,,,数据类型 **指针变量,,例如:,,,int,a,*p,**pp;,,a=2
21、2;,,p=,,pp=,,假设变量,a,的地址为4000,指针,p,的地址为4100,二级指针,pp,的地址为4800。,a、p、pp,三者的关系如上图。,&p=4100,&a=4000,22,pp(4800) p(4100) a(4000),10/3/2024,26,,C,语言程序设计教程,8.2 指针与函数,8.2.1 指针作为函数参数,,利用指针作函数参数,可以实现函数之间多个数据的传递,当形参为指针变量时,其对应实参可以是指针变量或存储单元地址。,,函数形参为指针变量,用,指针变量,或,变量地址,作实参,,,例8.3 编写一个交换两个变量的函
22、数,在主程序中 调用,实现两个变量值的交换。,10/3/2024,27,,C,语言程序设计教程,程序如下:,#,include<,stdio,.h>,,main(),,{,int,a,b;,,,int,*pa,*,pb,;,,void swap(,int,*p1,,int,*p2); /*,函数声明*/,,,scanf,(″%d%d″,,,pa=,,/* pa,指向变量,a */,,,pb,=,,/*,pb,指向变量,b */,,swap(pa,,pb,);,,printf,(″\,na,=%d,b=%d\n″,a,b);,,},或:,swap(,10/3/2024,28,,C,语
23、言程序设计教程,接上页:,void swap(,int,*p1,,int,*p2),,{,int,temp;,,temp=*p1; /*,交换指针,p1、p2,所指向的变量的值*/,,*,p1=*p2;,,,*p2=temp;,,},程序运行结果如下:,,输入:,12 22↙,,输出:,a=22,b=12,10/3/2024,29,,C,语言程序设计教程,分析以下,swap,函数能否实现交换:,,swap(,int,*p1,,int,*p2),,{,int,*p;,,*p=*p1;,,*,p1=*p2;*p2=*p;},,,,,swap(,int,x,,int,y),,{,int,t;t=x
24、,x=y;y=t;},,由于*,p,并不指向某一个变量,即其中的地址并不确定,可能造成系统破坏,由于函数的“值传递”,虽然交换了变量,x,y,的值,但并不能改变,a,b,的值。,10/3/2024,30,,C,语言程序设计教程,两点说明:,,(1) 若在函数体中交换指针变量的值,实参,a、b,的值并不改变,指针参数亦是传值。 例如:,,,int,*p; ,,p=p1; p1=p2; p2=p; ,,,不要希望如此完成处理。 ,,(2) 函数中交换值时不能使用无初值的指针变量作临时变量。 例如: ,,,int,*p; ,,*p=*p1; *p1=*p2; *p2=*p; ,,p,无
25、确定值,对,p,的使用可能带来不可预期的后果。,10/3/2024,31,,C,语言程序设计教程,8.2.2 指针函数,指针函数,:是指返回值为指针的函数,,指针函数的定义形式:,,,类型标示符 *函数名(参数),,例如:,,int,*fun(,int,a,,int,b),,{,,,函数体语句,,},,在函数体中有返回指针或地址的语句,形如:,,,return (&,变量名);,,或,return (,指针变量);,,并且返回值的类型要与函数类型一致。,,10/3/2024,32,,C,语言程序设计教程,例8.3 分析如下程序,main( ),,{,int,a,b,*p;,,int,
26、*max(,int,x,,int,y);,,scanf,(“%d,%d”,,,p=max(a,b);,,printf,(“max=%d”,*p);,,},,int,*max(,int,x,,int,y),,{ if x>y) return (,,else return (,,},10/3/2024,33,,C,语言程序设计教程,8.2.3 指向函数的指针,一个函数包括一组指令序列,存储在某一段内存中,这段内存空间的起始地址称为,函数的入口地址,,称函数入口地址为,函数的指针,。,函数名,代表函数的入口地址,,,可以定义一个指针变量,其值等于该函数的入口地址,指向这个函数,这样通过这个指
27、针变量也能调用这个函数。这种指针变量称为,指向函数的指针变量,。,,定义指向函数的指针变量的一般形式为,:,,,类型标识符(*指针变量名)( ),;,,例如:,,,int,(*p)(); /*,指针变量,p,可以指向一个整型函数*/,,,float (*q)(); /*,指针变量,q,可以指向一个浮点型函数*/,10/3/2024,34,,C,语言程序设计教程,刚定义的指向函数的指针变量,亦象其它指针变量一样要赋以地址值才能引用。当将某个函数的入口地址赋给指向函数的指针变量,就可用该指针变量来调用所指向的函数,,,给函数指针赋初值:将函数名(函数的入口地址值)赋给指针变量,,,例
28、如,,int,m, (*p)( );,,,,,int,max(,int,a,,int,b);,,则可以,p=max; /* p,指向函数,max() */,,指针调用函数的,,一般形式为,:,,(,*指针变量)( 实参表),;,,如上例,:,m=(*p)(12,22); /*,比较,m=max(12,22); */,10/3/2024,35,,C,语言程序设计教程,注意:,用函数指针调用函数是间接调用,没有参数类型说明,,C,编译系统也无法进行类型检查,因此,在使用这种形式调用函数时要特别小心。实参一定要和指针所指函数的形参类型一致。,,函数指针可以作为函数参数,此时,当函数指针每次
29、指向不同的函数时,可执行不同的函数来完成不同的功能,,,例 8.4,函数,max(),用来求一维数组的元素的最大值,在主调函数中用函数名调用该函数与用函数指针调用该函数来实现。,10/3/2024,36,,C,语言程序设计教程,程序如下:,#,include ",stdio,.h",,#define M 8,,main(),,{float,sumf,,sump;,,float a[M]={11,2,-3,4.5,5,69,7,80};,,float (*p)(); /*,定义指向函数的指针,p*/,,float max(float a[],,int,n); /*,函数
30、声明*/,,,p=max; /*,函数名(函数入口地址)赋给指针,p*/,,sump=(*p)(a,M); /*,用指针方式调用函数*/,,sumf,=max(a,M); /*,用函数名调用,max(),函数*/,,,printf,("sump=%.2f\n",sump);,,printf,(",sumf,=%.2f\n",,sumf,);,,},10/3/2024,37,,C,语言程序设计教程,程序接上页:,float max(float a[],,int,n),,{,int,k;,,float s;,,s=a[0];,,for (k=
31、0;k 32、的指针,,数组名是一个常量指针,它的值为该数组的首地址,,,1.指向数组的指针的定义方法与指向基本类型变量的指针的定义方法相同,,例如:,,int,a[10]={1,3,5,7,9};,,int,*p;,,p=&a[2],; (,把数组元素,a[2],的地址赋给指针变量,p),,p=a;,(,把数组的首地址赋给指针变量,p),10/3/2024,40,,C,语言程序设计教程,,C,语言规定,:数组名代表数组首地址,是一个地址常量,。,,因此,下面两个语句等价:,,,p=,,p=a;,,在定义指针变量的同时可赋初值:,,,int,a[10], *p= (,或,int,*p=a;),,等价于: 33、,int,*p;,,p=,两句,。,,10/3/2024,41,,C,语言程序设计教程,指向数组的指针变量,p,&a[0],1,3,15,17,19,p,a[0],:,a[9],,p[9],a+0,p+1,,或,a+1,p+9,,或,a+9,*(,a+9),或*(,p+9),,10/3/2024,42,,C,语言程序设计教程,2.通过指针引用数组元素,,,*,p=5;,,表示,对,p,当前所指的数组元素赋以一个值5。,,C,规定:,p+1,指向数组的下一元素(而不是将,p,值简单地加1)。,p+1,意味着使,p,的原值(地址),加,d,个字节(,d,为一个数组元素所占的字节数)。,如果,p,的 34、初值为&,a[0],,则:,,(1,),p+i,和,a+i,就是,a[i],的地址,或者说它们指向,a,数组的第,i,个元素(见下页图)。,,(2)*(,p+i),或,*(,a+i),是,p+i,或,a+i,所指向的数组元素,,即,a[i]。,,(3),指向数组的指针变量也可以带下标,如,p[i],与*,(,p+i)、 a[i],等价 。,10/3/2024,43,,C,语言程序设计教程,*(,p+i),a,数组,a[0],a[1],a[2],a[i],a[9],p,p+1,a+1,p+i, a+i,p+9, a+9,综上所述,引用一个数组元素有二法:,,(1)下标法:如,a[i],形式;,, 35、(2)指针法:如*(,a+i),或 *(,p+i)。,其中,a,是数组名,,p,是,指向数组的指针变量,其初值,p=a。,,10/3/2024,44,,C,语言程序设计教程,main(),,{,,int,a[10];,,int,i;,,for (i=0;i<10;i++),,scanf,("%d",,,printf,("\n");,,for (i=0;i<10;i++),,printf,("%d",,a[i],) ;,,},例8.5 用三种方法输出数组全部元素。,,(1),下标法,10/3/2024,45,,C,语言程序设计教程,main(),,{,int,a[10];,,int,i;,, 36、for (i=0;i<10;i++),,scanf,("%d",,,printf,("\n");,,for (i=0;i<10;i++),,printf,("%d",,*(a+i),);,,},(2),通过数组名计算数组元素地址,输出元素的值,10/3/2024,46,,C,语言程序设计教程,(3),用指针变量指向数组元素,,main(),,{,int,a[10];,,int,*p,i;,,for (i=0;i<10;i++),,scanf,("%d",,,printf,("\n");,,for (,p=a;p<(a+10);p++,),,printf,("%d",,*p,,);,,},三种方
- 温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。