第八章 地址和指针

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第八章 地址和指针
8.1 变量的地址和指针
a p
2001
一、概念 1、计算机内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号(称为内存地址)
2、若在程序中定义了一个变量,系统就会根据变量的类型为其分配一定字节数的内存空间,这样变量的内存地址也就确定了,即为该变量所在存储单元的第一个字节地址。

3、程序中对变量的存取操作实际是对某个地址的存储单元进行操作,这里的存取方式有两种:
1)直接存取:直接按变量的地址来存取变量值的方式
2)间接存取:通过一个间接变量p 来存放变量a 的地址,这样我们要存取a 先要找到p 的地址,从中找出a 的地址,然后再去访问由该地址所指向的存储单元。

这里,我们把存放地址的变量p 称为指针变量。

4、 说”指针变量p 指向了变量a ”的含义是指:指针变量p 中存放了变量a 的地址。

5、在某些场合,指针是使运算得以进行的唯一途径。

10
03
二、给指针变量赋值
一个指针变量可以通过不同的方式获得一个确定的地址值,从而指向一个具体的对象。

1、通过求地址运算符(&)获得地址值
1)单目运算符&用来求出运算对象的地址,以此可以把一个变量的地址赋给指针变量。

如:
int k,*p,*q; p=&k; 即把变量k 的地址赋予了p,
p k Array这时可以说p指向了k.
2) ①求地址运算符&只能应用于变量和数组元素,不能用于表达式、常量和register变量
②&运算符必须放在运算对象的左边,而且运算对象的类型必须与指针变量的基类型相同
3)在调用scanf函数时,如果有q=&k;时,那么scanf(%d”,&k)和scanf(“%d”,q)是等价的。

2、通过指针变量获得地址值
1)可以通过赋值运算把一个指针变量中的地址值赋给另一个指针变量,从而使这两个指针指向同一地址,如 p=q;
2)当进行赋值运算时,赋值号两边的指针变量的基类型
必须相同。

3、通过标准函数获得地址值
即通过调用库函数malloc和calloc在内存中开辟动态存储单元,从而把该存储单元的地址赋给指针变量。

﹡4、给指针变量赋“空”值
1)除了给指针变量赋地址值外,还可以给指针变量赋NULL值。

如:p=NULL;等价于p=’\0’;或p=0;
2)在使用NULL时,应该在程序的前面加预定行:#include <stdio.h>.
NULL的值为0,当执行了以上的赋值语句后,称p为空指针。

在这里,指针p并不是指向地址为0的存储单元。

8.2、对指针变量的操作
1、通过指针来引用一个存储单元
间接访问运算符(间址运算符)“*”是以单目运算符
1)int *p,i=10,j;
p=&i;
则j=*p; j=i; j=*(&i); j=*&i;
2)*p=*p+1; k=k+1; (*p)++; 这里括号不能少
如果写成*p++,则是先将*p作为表达式的值,然后使指针变量p本身加1,指向了下一个存储单元。

m=*p++; m=*p; p++;
k l h j
p
3)若有以下定义:
int **p,*s,k=20; s=&k; p=&s;
则变量p,s和k的关系可用下图表示:
p s k
这里的p为指向指针的指针变量。

2、应用举例
用指针指向两个变量,通过指针运算求出值小的那个数。

#include <stdio.h>
void main()
{int a,b,min,*pa,*pb,*pmin;
scanf(“%d%d”,pa,pb);
printf(“a=%d,b=%d\n”,a,b);
*pmin=*pa;
if(*pa>*pb) *pmin=*pb;
printf(“min=%d\n”,min);
}
以上程序说明当指针指向变量时,完全可以通过指针来对所
指存储单元进行存取操作。

二、移动指针
1、所谓移动指针是指对指针变量加上或减去一个整数,
或通过赋值运算使指针变量指向相邻的存储的单元。

注意:只有当指针指向一串连续的存储单元时,指针
移动才有意义。

a[0] a[1] a[2] a[3] a[4]
p q
这里可以有运算:q=p+2; p++; q--; q++;
2、当指针指向一串连续的存储单元时,可以对指向同一
串连续存储单元的两个指针进行相减的运算。

比如:q-p=2; *q-*p=33-11=22;
这里的“2”不是指十进制数“2”,而是指的是2个存储单元的长度,至于是多少个字节数,与该指针变量的基类型有关。

如p和q的基类型为int型,则对应的一个存储单元长度为4个字节。

3、当移动指针时,基类型为int 的指针只能用来指向int
变量,不能用来指向其他类型的变量,否则,当移动
指针时,对于整数“1”,系统将按照基类型来确定移
动多少个字节。

a[0] a[1] a[2] a[3] a[4]
p q
三、指针比较
在关系表达式中,可以对两个指针进行比较。

比如:int a[5]={11,22,33,44,55},*p,*q;
p=a[0]; q=a[2];
if(p<q) printf(“p<q”);
else pintf(“p>q”);
8.3 指针在函数中的应用及举例
一、形参为指针变量时实参和形参之间的数据传递
1)若函数的形参为指针类型,调用该函数时,对应的实参必须是基类型相同的地址值或者是已赋值的指针变量。

2)例如:编写函数add(int *a,int *b),函数中把指针a和b 所指的存储单元中的两个值相加,然后将和作为函数值返回。

#include <stdio.h>
int add(int *a,int *b)
{int sum;
sum=*a+*b;
return sum; }
void main()
{int x,y,z;
printf(“input x and y:”);
scanf(“%d%d”, &x,&y);
z=add(&x,&y);
printf(“%d+%d=%d\n”,x,y,z);
}
二、通过传送地址值在被调用函数中直接改变调用函数中变量的值
1)把数据从被调函数返回调用函数的唯一途径是通过return语句返回函数值,因此就限定了只能返回一个值。

下面我们通过举例实现将两个或两个以上的数据从被调函数返回到调用函数。

2 )举例1
#include <stdio.h>
void swap(int *a,int *b)
{ int t;
printf(“(2)a=%d b=%d\n”,*a,*b);
t=*a; *a=*b; *b=t;
printf(“(3)a=%d b=%d\n”,*a,*b);
}
void main()
{int x=30,y=20;
printf(“(1)x=%d y=%d\n”,x,y);
swap(&x,&y);
printf(“(4)x=%d y=%d\n”, x,y);
}
说明:没有通过return语句返回值,所以swap函数类型定义为void型,从上述例子中,我们可以通过传送地址的方式在被调函数中直接改变调用函数中变量的值,从而来达到数据之间的传递。

3)编写函数,使调用函数中的第一个实参总是存放两个数中较小的数,第二个参数存放较大的数。

#include <stdio.h>
void order( int *a, int *b)
{int t;
if(*a>*b) {t=*a; a=b; *b=t;}
}
void main()
{int x,y;
printf(“input x and y:”);
scanf(“%d%d”,&x,&y);
printf(“x=%d,y=%d\n”,x,y);
order(&x,&y);
printf(“x=%d,y=%d\n”,x,y);
}
说明:在order函数,if(*a>*b)实际上是比较main函数中变量x和y的值。

三、函数返回地址值
函数值的类型除了可以是简单的数据类型外,还可以是指针类型。

例如:编写函数把主函数中存放较大数的地址作为函数值返回。

#include <stdio.h>
int *fun(int *a,int *b)
{if (*a>*b) return a;
else return b;
}
void mian()
{int *p,m,n;
printf(“input m and n:”);
scanf(“%d%d”,&m,&n);
printf(“m=%d,n=%d\n”,m,n);
p=fun(&m,&n);
printf(“m=%d,n=%d,*p=%d\n”,m,n,*p);
}
输入:99 101
输出:m=99,n=101,*p=101.
8.4 习题讲解:
1.有以下程序(2009年真题)
#include <stdio.h>
void f(int *p,int *q);
void main()
{int m=1,n=2,*r=&m;
f(r,&n); printf(“%d,%d”,m,n);
}
void f(int *p,int *q)
{p=p+1; *q=*q+1;}
则程序运行后的输出结果为_A___
A) 1,3 B)2,3 C)1,4 D)1,2
2.(2009年3月真题)
有以下程序:
# include <stdio.h>
void fun(int *a,int *b)
{int *c;
c=a;a=b;b=c;
}
void main()
{int x=3,y=5,*p=&x,*q=&y;
fun(p,q);printf("%d,%d,",*p,*q);
fun(&x,&y);printf("%d,%d\n",*p,*q);
}
程序运行后的输出结果是__B____
A)3,5,5,3 B)3,5,3,5 C)5,3,3,5 D)5,3,5,3
3.有以下程序:(2009年3月真题)
# include <stdio.h>
void fun(char *s)
{while(*s)
{if (*s%2==0) printf("%c",*s);
s++;
}
}
void main()
{char a[]={"good"};
fun(a);printf("\n");
}
注意:字母a的ASCII码值为97,程序运行后的输出结果是: A) d B)go C)god D) good
4. 有以下程序:
#include <stdio.h>
int b=2;
int fun(int *k)
{ b=*k+b; return (b); }
void main()
{int a[10]={1,2,3,4,5,6,7,8},i;
for(i=2;i<4;i++) {b=fun(&a[i])+b;}
printf(“\n”);
}
程序运行后的输出结果是__C___
A) 10 12 B)8 10 C)10 28 D)10 16
5.(P102 8.3)若有以下程序:
#include <stdio.h>
void sub(int x,int y,int *z)
{*z=y-x; }
void main()
{int a,b,c;
sub(10,5,&a); sub(7,a,&b); sub(a,b,&c);
printf(“%d,%d,%d\n”,a,b,c); }
6. (P102 8.4)若有以下程序:
#include “stdio.h”
void main()
{int k=2,m=4,n=6,*pk=&k,*pm=&m,*p;
*(p=&n)=*pk*(*pm); printf(“%d\n”,n) }
则程序的输出结果是
A) 4 B)6 C) 8 D)10
7. (P102 8.5)若指针p 已正确定义并指向如图所示的存储单元:a[0] a[1] a[2] a[3] a[4]
则执行语句*p++后,*p的值是:
A) 20 B)30 C)21 D)31
8. (P102 8.6) 若指针p 已正确定义并指向如图所示的存储单元,则表达式*++p的值是:
A) 20 B)30 C)21 D)31
9. (P102 8.7)若指针p 已正确定义并指向如图所示的存储单元, 则表达式++*p的值是:
A)20 B)30 C)21 D)31
10. (P103 8.11) 若有以下程序:
#include “stdio.h”
void sub(double x, double *y, double *z)
{*y=*y-1.0; *z=*z+x; }
void main()
{double a=2.5,b=9.0,*pa,*pb;
pa=&a; pb=&b;
sub(b-a,pa,pa); printf(“%f\n”,a); }
11. 编程,请编写函数,对传送过来的三个数选出最大数和最小数,并通过形参传回调用函数。

(用指针实现)
#include “stdio.h>
void swap(int *p1,int *p2,int *p3)
{int t;
if(*p1>*p2) {t=*p1,*p1=*p2,*p2=t;}
if(*p1>*p3) {t=*p1,*p1=*p3,*p3=t;}
if(*p2>*p3) {t=*p2,*p2=*p3,*p3=t;}
}
void main()
{int a,b,c;
scanf(“%d%d%d”,&a,&b,&c);
swap(&a,&b,&c);
printf(“min=%d,max=%d\n”,a,c);
}
12. 编写函数对传送过来的两个浮点数求和与差,并通过函数调用传回调用函数。

#include "stdio.h"
void fun(double x,double y,double *s1,double *s2)
{*s1=x+y; *s2=x-y;}
void main()
{double a,b;
scanf("%lf,%lf",&a,&b);fun(a,b,&a,&b); printf("%f,%f\n",a,b);}。

相关文档
最新文档