第8章善于利用指针8.1指针是什么8.2指针变量8.3通过指针引用数组8.4通过指针引用字符串1.变量的“直接访问”方式:i2000H3直接访问:按变量的地址(即变量名)存取变量值的方式。例如:inti=3;讨论一个问题:A、B和C三人约定住宿在某旅馆。A先到达旅馆,在服务台登记了房间,房间号是2010。然后,A电话通知了B,但没有通知C。B怎样找到A呢?B可以直接到2010找到A.inti=3,j=6,k;printf(“%d”,i);通过变量名i找到i的地址2000H,从而从存储单元读取3讨论一个问题:A、B和C三人约定住宿在某旅馆。A先到达旅馆,在服务台登记了房间,房间号是2010。然后,A电话通知了B,但没有通知C。C怎样找到A呢?C可以从旅馆的服务台查询到A的房号2010,间接找到A。将变量的地址放在另一个内存单元中,先到另一个内存单元中取得变量的地址,再由变量的地址找到变量并进行数据存取(见下图)。2.变量的“间接访问”方式间接访问方式:3i2000H2000Hi_pointer作用相当服务台inti=3,j=6,k;定义特殊变量i_pointer将i的地址存到这里间接存取i_pointer=&i;*i_pointer=50;508.1指针是什么地址:内存中存储单元的编号。指针:在C在语言中一个变量的地址称为该变量的“指针”。例如:inta;/*&a即为变量a的地址(指针)*/8.2指针变量8.2.1使用指针变量的例子8.2.2怎样定义指针变量8.2.3怎样引用指针变量8.2.4指针变量作为函数参数例8.1通过指针变量访问整型变量。#includestdio.hintmain(){inta=100,b=10;int*p1,*p2;p1=&a;p2=&b;printf(a=%d,b=%d\n,a,b);printf(*p1=%d,*p2=%d\n,*p1,*p2);return0;}8.2.1使用指针变量的例子p1&a*p1a//定义整型变量,并初始化//定义指向整型数据的指针变量//为指针变量p1赋值//为指针变量p2赋值8.2.2怎样定义指针变量定义指针变量的一般形式为:类型*指针变量名;如:int*p1,*p2;int是为指针变量指定的“基类型”。基类型指定指针变量可指向的变量类型。p1,p2是指针变量名,而不是*p1,*p2如p1可以指向整型变量,但不能指向浮点型变量。例如:inta;floatb;int*p;p=&a;p=&b;正确错误8.2.3怎样引用指针变量在引用指针变量时,可能有三种情况:给指针变量赋值。如:p=&a;引用指针变量指向的变量。如有p=&a;*p=1;则执行printf(“%d”,*p);输出1引用指针变量的值。如:printf(“%x”,p);使p指向a*p相当于a以十六进制输出a的地址8.2.3怎样引用指针变量1、&取址运算功能:返回其后随变量的内存地址例:int*p,m;/*定义p为指向int类型变量的指针*/m=200;p=&m;/*将m的地址赋给指针变量p*/pm2010H2002010H&m8.2.3怎样引用指针变量2、*间接存取运算功能:返回其后随地址(指针变量值)中的变量值例:int*p,m;p=&m;/*p指向整型变量m*/*p=200;/*将200赋给指针变量p所指向的变量m*/pm&m200执行语句*p=200;指针变量的赋值:变量的指针(地址)是一个无符号整数,可以将一个变量的指针赋值给一个指针变量,但不能将一个整数直接赋值给一个指针变量。1、用变量的地址给指针变量赋值(求地址运算符&)。例如:inta,b,*p1;p1=&a;注意:变量的类型必须与指针变量的类型相同。2、用相同类型的指针变量赋值。例如:inta,*p1,*p2;p1=&a;p2=p1;注意:指针变量若不赋值,则指针变量的值是随机的。危险8.2.3怎样引用指针变量例main(){inti=10,b=3;int*p;*p=i;printf(“%d”,*p);}危险!例main(){inti=10,k;int*p;p=&k;*p=i;printf(“%d”,*p);}指针变量p随机指针变量必须先赋值,再使用3…...…...2000200420062005整型变量i10200120022003整型变量b10(2)指针变量不赋值,指针变量的值是随机的,指向也是随机的,具有不确定性;3、赋空值NULL例如:int*p;p=NULL;或p=0;指针变量赋空值NULL与不赋值的区别:(1)指针变量赋空值NULL,指向为0的单元,系统保证该单元不作它用,表示指针变量值没有意义;用途:避免指针变量的非法引用,在程序中常作为状态比较4、void*类型指针void*p;表示不指定p是指向哪一种类型数据的指针变量使用时要进行强制类型转换取指针变量所指向地址内容:b=*p;存指针变量所指向地址内容:*p=50;例如:main(){inta=5,b=3,*p;p=&a;b=*p+3;*p=4;printf(“a=%d,b=%d”,a,b);}4000pa2000b3100*p200035运行结果:a=4,b=884注意:*p若出现在“=”的右边或其他表达式中则为取内容*p若出现在“=”的左边则为存内容例8.2输入a和b两个整数,按先大后小的顺序输出a和b。#includestdio.hintmain(){int*p1,*p2,*p,a,b;printf(pleaseentertwointegernumbers:);scanf(%d,%d,&a,&b);p1=&a;p2=&b;if(ab){p=p1;p1=p2;p2=p;}printf(a=%d,b=%d\n,a,b);printf(max=%d,min=%d\n,*p1,*p2);return0;}#includestdio.hvoidmain(){inta=5,b=8;intt;printf(“a=%d,b=%d\n”,a,b);t=a;a=b;b=t;printf(“a=%d,b=%d\n”,a,b);}#includestdio.hvoidmain(){inta=5,b=8;int*pa=&a,*pb=&b;intt;printf(“a=%d,b=%d\n”,a,b);t=*pa;*pa=*pb;*pb=t;printf(“a=%d,b=%d\n”,a,b);}例题1:交换a,b两个数直接访问间接访问例题2:编写一个函数实现两个数的交换#includestdio.hvoidswap(intx,inty){intt;t=x;x=y;y=t;}voidmain(){inta=3,b=5;swap(a,b);printf(“a=%d,b=%d\n”,a,b);}5a2010Hb2B12Hx3100Hy3F02H35335533t4D24H不能实现两个数的交换参数之间是值传递,单向(从实参传递给形参)例题3:#includestdio.hvoidswap(int*x,int*y){intt;t=*y;*y=*x;*x=t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}5a2010Hb2B12Hx3100Hy3F02H20102B123335t4A10H5能实现两个数的交换8.2.4指针变量作为函数参数例题3:#includestdio.hvoidswap(int*x,int*y){intt;t=*y;*y=*x;*x=t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}5a2010b2B123335c语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式。指针变量作函数参数也要遵循这一规则。调用函数不可能改变实参指针变量的值,但是可以改变实参指针变量所指变量的值。例题4:#includestdio.hvoidswap(int*x,int*y){int*t;t=x;x=y;y=t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}5a2010b2B12x3100y3F0220102B1232B122010t4C002010不能实现两个数的交换1.实参和形参都是指针变量2.被调函数中修改指针所指向的空间的值(即修改*p的值)指针作为参数,地址传递的条件:voidswap(int*x,int*y){intt;t=*y;*y=*x;*x=t;}voidswap(int*x,int*y){int*t;t=x;x=y;y=t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}//能实现交换功能的函数//不能实现交换功能的函数#includestdio.hvoidswap(int*x,int*y){int*t;*t=*x;*x=*y;*y=*t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}有问题:指针变量t没有指向对象,语句存在危险#includestdio.hvoidswap(int*x,int*y){int*t,w;t=&w;*t=*x;*x=*y;*y=*t;}voidmain(){inta=3,b=5;swap(&a,&b);printf(“a=%d,b=%d\n”,a,b);}能够实现两个数的交换指针变量的种类指针变量的值指向对象的值表达形式指向变量的指针变量pa==&a*pa==a例如:inta,*pa;pa=&a;指针变量说明表格要求:”*”后面必须是地址表达式,&后面是变量*和&运算符的关系:互为逆运算8.3通过指针引用数组8.3.1数组元素的指针8.3.2在引用数组元素时指针的运算8.3.3通过指针引用数组元素8.3.4用数组名作函数参数8.3.5通过指针引用多维数组8.3.1数组元素的指针数组元素在内存中是连续存放的一个数组包含若干元素,每个数组元素都有相应的地址。inta[10];数组a中下标为i(假设i的取值合理)的数组元素的地址:&a[i]第二种表达形式:C语言中数组中下标为0的数组元素地址为:数组名或数组名+0C语言中数组中下标为i的数组元素地址为:数组名+i8.3.1数组元素的指针所谓数组元素的指针就是数组元素的地址。指针变量可以指向数组元素(把某一元素的地址放到一个指针变量中)。可以用一个指针变量指向一个数组元素inta[10]={1,3,5,7,9,11,13,15,17,19};int*p;p=&a[0];注意:数组名a是数组首元素的地址,是一级指针。“p=a;”的作用是“把a数组的首元素的地址赋给指针变量p”。即p&a[0]a8.3.2在引用数组元素时指针的运算在指针指向数组元素时,允许以下运算:加一个整数(用+或+=),如p+1p计算p++低高p++==p指向下一数据存储单元(向后移动4个字节)++:指针向高地址方向移动一个数据存储单元pp8.3.2在引用数组元素时指针的运算在指针指向数组元素时,允许以下运算:减一个整数(用-或-=),如p-1p--:指针向低地址方向移动一个数据存储单元p――==p指向前一数据存储单元(向前移动4个字节)计算p――低高pp注意:数据类型不同,指针增1和减1运算所引起的地址变化量是不同的,指向的新地址为:原地址sizeof(类型说明符)例:inta[32],i*p;下标法对数组进行运算for(i=0;i32;i++)scanf(“%d”,&a[i]);指针法对数组进行运算p=a;for(i=0;i32;i++)scanf(“%d”,p++);例:inta[10],*p;p=&a[2];计算:++p表达式值