返回8.1指针与指针变量8.2指针与函数8.3指针与数组8.4指针与字符串8.5指针数组于命令行参数8.6程序举例8.1指针与指针变量8.1.1指针的概念1.内存与变量地址内存地址:内存是计算机用于存储数据的存储器,以一个字节作为存储单元,为了便于访问,给每个字节单元一个唯一的编号,第一字节单元编号为0,以后各单元按顺序连续编号,这些单元编号称为内存单元的地址。变量地址:变量所分配存储空间的首字节单元地址(字节单元编号)。下一页第8章指针上一页2.变量的三要素:名字、类型与值每个变量都通过变量名与相应的存储单元相连系,具体分配哪些单元给变量,由C编译系统完成变量名到对应内存单元地址的变换。变量分配存储空间的大小由类型决定。变量的值则是指相应存储单元的内容。3.内存存取方式直接存取:把直接按变量名或地址存取变量值的方式称为“直接存取”方式。间接存取:通过定义一种特殊的变量专门存放内存或变量的地址,然后根据该地址值再去访问相应的存储单元。下一页第8章指针上一页系统为特殊变量p(用来存放地址的)分配的存储空间地址是4800,p中保存的是变量a的地址,即4000,当要读取a变量的值12345时,不是直接通过a变量,也不是直接通过保存12345的内存单元的地址4000去取值,而是先通过变量p得到p的值4000,即a的地址,再根据地址4000读取它所指向单元的值12345。这种间接的通过变量p得到变量a的地址,再存取变量a的值的方式即为“间接存取”。通常称变量p指向变量a,变量a是变量p所指向的对象…400012345400040024800pap(4800)p(4800)a(4000)4000123454000间接存取示意图右下一页第8章指针上一页4.指针的概念在C语言中,用指针来表示一个变量指向另一个变量这样的指向关系。所谓指针即地址。一个变量的指针即该变量的地址,如4000就是指向变量a的指针。指针变量:专门存放地址的变量,如p即是一个指针变量,它存放的是a的地址4000。下一页第8章指针上一页8.1.2指针变量的定义与初始化1.指针变量的定义类型标识符*指针变量名;在指针变量定义中,*是一个说明符,它表明其后的变量是指针变量,如p是指针变量,而不要认为“*p”是指针变量。指针变量定义时指定的数据类型不是指针变量本身(变量存放的值)的数据类型,而是指针变量所指向的对象(或称目标)的数据类型指针变量存放的是所指向的某个变量的地址值,而普通变量保存的是该变量本身的值指针变量并不固定指向一个变量,可指向同类型的不同变量下一页第8章指针上一页例:float*p1;(定义p1为指向实型变量的指针变量)char*p2;(定义p2为指向字符型变量的指针变量)(1)指针运算符与地址运算符与指针引用有关的两个运算符:&与*。&:取地址运算符*:指针运算符,或称指向运算符、间接访问运算符。指针指向的对象的表示形式:*指针变量此处*是访问指针所指对象的运算符,与指针定义时的*不同。2.指针变量初始化下一页第8章指针上一页(2)指针变量初始化若有定义:inta,*p;语句仅仅定义了指针变量p,但指针变量并未指向确定的变量(或内存单元)。因为这些指针变量还没有赋给确定的地址值,只有将某一具体变量的地址赋给指针变量之后,指针变量才指向确定的变量(内存单元)。指针变量初始化:在定义指针时同时给指针一个初始值如:inta,*p=&a;40003a(4000)p*p下一页第8章指针上一页(3)指针变量的引用①*指针变量名——代表所指变量的值。②指针变量名——代表所指变量的地址。有定义:inta,*p=&a;用*p来表示p指向的对象a,*p与a是等价的。*p可以象普通变量一样使用。例如:a=12;*p=12;scanf(%d,&*p);scanf(%d,p);printf(“%d%d”,*p,a);注意:*与&具有相同的优先级,结合方向从右到左。这样,&*p即&(*p),是对变量*p取地址,它与&a等价;p与&(*p)等价,a与*(&a)等价。下一页第8章指针上一页8.1.3指针运算1.指针的赋值运算(1)将变量地址值赋给指针变量,使指针指向该变量。设有如下定义:inta,b,*pa,*pb;float*pf;第一行定义了整型变量a,b及指针变量pa,pb。pa、pb还没有被赋值,因此pa、pb没有指向任何变量,下面语句完成对pa,pb的赋值:pa=&a;pb=&b;下一页第8章指针上一页例如:intj,k;int*pointer1,*pointer2;pointer1=&j;pointer2=&k;pointer1jpointer2k下一页第8章指针上一页(2)相同类型的指针变量间的赋值pa与pb都是整型指针变量,它们间可以相互赋值,如:pb=pa;即pa,pb都指向变量a,此时a、*pa、*pb是等价的。指针指向变化如下图:注意:只有相同类型的指针变量才能相互赋值,如pf=pa;是不允许的。因为pa是整型指针,pf是浮点型指针。&a&bpapba,*pab,*pb&a&apapba,*pa,*pbb下一页第8章指针上一页(3)给指针变量赋空值给指针变量赋空值,说明该指针不指向任何变量。“空”指针值用NULL表示,NULL是在头文件stdio.h中预定义的常量,其值为0,在使用时应加上预定义行,如:#includestdio.hint*pa=NULL;亦可以用下面的语句给指针赋“空值”:pa=0;或:pa=’\0’;这里指针pa并非指向0地址单元,而是具有一个确定的“空值”,表示pa不指向任何变量。注意:指针虽然可以赋值0,但却不能把其它的常量地址赋给指针。例如:pa=4000;是非法的。下一页第8章指针上一页例8.1指针定义与初始化main(){inta,b;int*pointer_1,*pointer_2;a=100;b=10;pointer_1=&a;pointer_2=&b;printf(%d,%d\n,a,b);printf(%d,%d\n,*pointer_1,*pointer_2);}下一页第8章指针上一页程序运行结果:100,10100,10&a&bbPointer_1Pointer_2a*pointer_1*pointer_2下一页第8章指针上一页例8.2从键盘上输入两个整数到a、b,按由大到小输出。#includestdio.hmain(){inta,b,*pa=&a,*pb=&b,*p;/*定义指针变量pa、pb,如下页图a*/scanf(″%d%d″,&a,&b);if(*pa<*pb){p=pa;/*进行指针交换,如下页图b,c*/pa=pb;pb=p;}printf(″\na=%d,b=%d\n″,a,b);printf(″\nmax=%d,min=%d″,*pa,*pb);/*pa指向大数,pb指向小数*/}下一页第8章指针上一页若输入:1222↙输出结果:a=12,b=22max=22,min=12(a)(b)(c)指针变化示意图1222ppapbpapbab下一页第8章指针上一页1222ppapb2.指针的算术运算(1)加减运算:一个指针可以加、减一个整数n,其结果与指针所指对象的数据类型有关。指针变量的值应增加或减少“n×sizeof(指针类型)”。加减运算常用于数组的处理。对指向一般数据的指针,加减运算无实际意义。例如:inta[10],*p=a,*x;x=p+3;/*实际上是p加上3*2个字节赋给x,x指向数组的第三个分量*/对于不同基类型的指针,指针变量“加上”或“减去”一个整数n所移动的字节数是不同的。例如:floata[10],*p=a,*x;p=p+3;/*实际上是p加上3*4个字节赋给x,x依然指向数组的第三个分量*/下一页第8章指针上一页(2)自增自减运算指针变量自增、自减运算具有上述运算的特点,但有前置后置、先用后用的考虑,务请小心。例如:inta[10],*p=a,*x;x=p++/*x第一个元素分量,p指向第二个元素*/x=++p;/*x、p均指向数组的第二个分量*/*p++相当于*(p++)。*(p++)与(*p)++含义不同,前者表示地址自增,后者表示当前所指向的数据自增。下一页第8章指针上一页1.若有定义inta,*p;执行了“p=&a”,则:“&*p”的含意是什么?下一页第8章指针上一页思考(答:相当于&a)2.*&a的含意是什么?(答:a)(答:a++)3.(*p)++相当于什么?3.指针的关系运算与基本类型变量一样,指针可以进行关系运算。在关系表达式中允许对两个指针进行所有的关系运算。若p,q是两个同类型的指针变量,则:p>q,pq,p==q,p!=q,p=q都是允许的。指针的关系运算在指向数组的指针中广泛的运用,假设p、q是指向同一数组的两个指针,执行p>q的运算,其含义为,若表达式结果为真(非0值),则说明p所指元素在q所指元素之后。或者说q所指元素离数组第一个元素更近些。注意:在指针进行关系运算之前,指针必须指向确定的变量或存储区域,即指针有初始值;另外,只有相同类型的指针才能进行比较。下一页第8章指针上一页8.1.4多级指针把指向指针型数据的指针变量称为指向指针的指针,或称多级指针。二级指针的定义形式如下:数据类型**指针变量例如:inta,*p,**pp;a=22;p=&a;pp=&p;假设变量a的地址为4000,指针p的地址为4100,二级指针pp的地址为4800。a、p、pp三者的关系如上图。&p=4100&a=400022pp(4800)p(4100)a(4000)第8章指针上一页返回8.2指针与函数8.2.1指针作为函数参数利用指针作函数参数,可以实现函数之间多个数据的传递,当形参为指针变量时,其对应实参可以是指针变量或存储单元地址。函数形参为指针变量,用指针变量或变量地址作实参例8.3编写一个交换两个变量的函数,在主程序中调用,实现两个变量值的交换。下一页第8章指针上一页#includestdio.hmain(){inta,b;int*pa,*pb;voidswap(int*p1,int*p2);/*函数声明*/scanf(″%d%d″,&a,&b);pa=&a;/*pa指向变量a*/pb=&b;/*pb指向变量b*/swap(pa,pb);printf(″\na=%d,b=%d\n″,a,b);}voidswap(int*p1,int*p2){inttemp;temp=*p1;/*交换指针p1、p2所指向的变量的值*/*p1=*p2;*p2=temp;}或:swap(&a,&b);下一页第8章指针上一页程序运行结果如下:输入:1222↙输出:a=22,b=12(1)若在函数体中交换指针变量的值,实参a、b的值并不改变,指针参数亦是传值。int*p;p=p1;p1=p2;p2=p;不要希望如此完成处理。(2)函数中交换值时不能使用无初值的指针变量作临时变量。例如:int*p;*p=*p1;*p1=*p2;*p2=*p;p无确定值,对p的使用可能带来不可预期的后果。下一页第8章指针上一页两点说明8.2.2指针函数指针函数:是指返回值为指针的函数指针函数的定义形式:类型标示符*函数名(参数)例如:int*fun(inta,intb){函数体语句}在函数体中有返回指针或地址的语句,形如:return(&变量名);或return(指针变量);并且返回值的类型要与函数类型一致。下一页第8章指针上一页例8.3分析如下程序main(){inta,b,*p;int*max(intx,inty);scanf(“%d,%d”,&a,&b);p=max(a,b);printf(“max=%d”,*p);}int*max(intx,inty){ifxy)return(&x);elsereturn(&y);}下一页第8章指针上一页8.2.3指向函数的指针一个函数包括一组指令序列,存储在某一段内存中,这段内存空间的起始地址称为函数的入口地址称函数入口地址为函数的指针。