第8章 指针Word格式.docx
- 文档编号:22677199
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:21
- 大小:54.29KB
第8章 指针Word格式.docx
《第8章 指针Word格式.docx》由会员分享,可在线阅读,更多相关《第8章 指针Word格式.docx(21页珍藏版)》请在冰豆网上搜索。
然后从由2000开始的两个字节中取出数据(即
变量的值3),把它输出。
输入时如果用scanf
("
%d"
,&
i),在执行时,就把从键盘输入的值送到地址为2000开始的整型存储单元中。
如果有语句k=i+j,则从2000开始的两字节取出i的值(3),再从2002开始的两字节取出j的值(6),将它们相加后再将其和(9)送到k所占用的2004、2005字节单元中。
这种按变量地址存取变量值的方式称为“直接访问”方式。
还可以采用另一种称之为“间接访问”的方式,将变量i的地址存放在另一个变量中。
按C语言的规定,可以在程序中定义整型变量、实型变量、字符变量等,也可以定义这样
一种特殊的变量,它是存放地址的。
假设我们定义了一个变量i_pointer,用来存放整型变
量的地址,它被分配为3010、3011字节。
可以通过下面语句将i的地址(2000)存放到
i_pointer中:
i_pointer=&
i;
这时,i_pointer的值就是2000,即变量i所占用单元的起始地址。
要存取变量i的值,也可以采用间接方式:
先找到存放“i的地址”的变量,从中取出i的地址(2000),然后到2000、2001字节取出i的值(3)。
打个比方,为了开一个A抽屉,有两种办法,一种是将A钥匙带在身上,需要时直接找出该钥匙打开抽屉,取出所需的东西。
另一种办法是:
为安全起见,将该A钥匙放到另一抽屉B中锁起来。
如果需要打开A抽屉,就需要先找出B钥匙,打开B抽屉,取出A钥匙,再打开A抽屉,取出A抽屉中之物,这就是“间接访问”。
所谓“指向”就是通过地址来体现的。
i_pointer中的值为2000,它是变量i的地址,这样就在i_pointer和变量i之间建立起一种联系,即通过lpointer能知道i的地址,从而找到变量i的内存单元。
由于通过地址能找到所需的变量单元,我们可以说,地址“指向”该变量单元(如同说,
房间号“指向“某一房间一样)。
因此在C语言中,将地址形象化地称为“指针”。
意思是通过它能找到以它为地址的内存单元(例如根据地址2000就能找到变量i的存储单元,从而读取其中的值)。
一个变量的地址称为该变量的“指针”。
例如,地址2000是变量i的指针。
如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。
上述的i_pointer就是一个指针变量。
指针变量的值(即指针变量中存放的值)是指针(地址)。
请区分“指针”和“指针变量”这两个概念。
例如,可以说变量i的指针是2000,而不能说i的指针变量是2000(而是i_pointer);
同样,变量i_pointer的指针是3010,而i_pointer的指针变量是pp,…等等,换句话说,变量的指针就是变量的地址,而指针变量就是存放地址的变量。
ii_pointerpp
200030107066
二、变量的指针和指向变量的指针变量
1、定义指针类型
指针类型:
指针是具有类型的,它的类型就是它所指向的实体的类型。
如前面的i_pointer为指向int类型的指针。
指针定义:
(类型名)*(指针变量名)
如前面所述的指针变量定义为:
inti;
//定义整形变量i
int*i_pointer;
//定义整形指针变量
指针变量的赋值:
将变量的地址赋给指针变量。
如i_pointer=&
i;
可以形象的描述为:
i_pointeri或*i_pointer
2、指针变量的引用
在定义了一个指针变量后可以对该指针变量进行各种操作,在C语言中有两个关于指针的运算符&
和*:
&
——取地址运算符,如&
a的值为变量a的地址。
*——指针运算符,如*i_pointer表示指针i_pointer指向的变量,上例图中表示*i_pointer与i是相同的变量。
对语句中使用变量i的称为直接引用,而若在语句中使用*i_pointer称为间接引用。
例10.1指针变量的引用(P201)
#include"
stdio.h"
main()1000p1p1a(或*p1)
{1004p2
int*p1,*p2,a,b;
scanf("
%d%d"
&
a,&
b);
p2b(或*p2)
p1=&
a;
p2=&
;
printf("
%d,%d\n"
a,b);
*p1,*p2);
1024i1
p2=p1;
1028i2
}物理示意图逻辑示意图
3、指针变量作为函数的参数
例10.3
voidswap(int*p1,int*p2)//交换两个数据的函数a
{inttemp;
p1
temp=*p1;
*p1=*p2;
*p2=temp;
}b
main()//主函数p2
{inta=3,b=5
swap(&
b);
//a,b交换了数据
print(“a=%d,b=%d\n”,a,b);
}
注意:
这里的关键是swap函数中采用了“间接交换”数据的方法,若写成:
voidswap(int*p1,int*p2)
{int*temp;
temp=p1;
p1=p2;
p2=temp;
}
则达不到上述结果。
三、数组的指针和指向数组的指针
1、一维数组的指针表示法
前面已经介绍,一个数组名代表它的起始地址。
假设有一整型数组inta[5],如下图所示:
a1010a[0]
a+11012a[1]
a+21012a[2]
a+31012a[3]
a+41012a[4]
即一维数组名a表示一个地址,一般有如下的等价表示法:
a与&
a[0],a+1与&
a[1],……a+i与&
a[i]——它们都表示同一地址;
*a与a[0],*(a+1)与a[1],……*(a+i)与a[i]——它们都表示同一数据;
对数组的数据用*(a+i)则引用称为地址法,而用a[i]引用则称为下标法。
例10.5分别用下标法、地址法访问数组的元素
main()
{inta[5]={1,3,5,7,9},i,*p;
for(i=0;
i<
5;
i++)
%d"
a[i]);
//下标法
\n"
);
*(a+i));
//地址法1
for(p=a;
p<
a+5;
p++)
*p);
//地址法2
三种方法的比较:
下标法与地址法1效率相同,实际上编译后下标法便转化为地址
法1,而地址法2效率最高,因每次循环不用重新计算地址。
例10.6通过指针变量输出数组元素
main()p
{inta[10],i,*p;
a[0]
p=a;
p+1a[1]
10;
p++);
i++,p++)
}
2、用数组名作为函数参数(P213)
用数组作为函数的参数。
在调用时,系统不是把数组的值传递给形参,而是把实参的起止地址传递给形参,也就是说作为形参的数组与实参的数组共占同一内存单元,这样,形参数组中的元素的任何变化在实参数组中元素当然也作同样的变化(见p164)。
而指针是用来存放地址的,所以用数组作为函数的参数,相当于用指针来作为形式参数,实际上,C编译都是把形参数组作为指针变量来处理。
如函数f(intarr[],intn)与函数f(int*arr,intn)是等价的。
例10.7分别用数组和指针作为形参,实现数组中元素的倒置。
(P217、P222)
voidinv(intx[],intn)
{
inttemp,i,j,m=(n-1)/2;
=m;
{j=n-1-i;
temp=x[i];
x[i]=x[j];
x[j]=temp;
return;
{inti,a[10]={3,7,9,11,0,6,7,5,4,2};
%d,"
inv(a,10);
改用指针变量作为函数的形参:
voidinv(int*x,intn)
int*p,temp,*i,*j,m=(n-1)/2;
i=x;
j=x+n-1;
p=x+m;
for(;
=p;
i++,j--)
{temp=*i;
*i=*j;
*j=temp;
}
3、指向多维数组的指针和指针变量
因为二维数组可以解释为以一维数组为元素的一维数组。
即二维数组a[m][n]可以看成一维数组(a[0],a[1],…,a[m-1]),
其中a[0]又是这样的一维数组(a[0][0],a[0][1],…,a[0][n-1]),即m行n列矩阵的第0行,
a[1]又是这样的一维数组(a[1][0],a[1][1],…,a[1][n-1]),即m行n列矩阵的第1行…...
因此,在二维数组a中,a[0],a[1],…,a[m-1]是表示地址而不是表示数据(因为一维数组名表示地址而不是表示数据),如下图所示:
aa[0]a00a01a02a03…a0n-1
a+1a[1]a10a11a12a13…a1n-1
……………
a+(m-1)a[m-1]am-1,0am-1,1…am-1,n-1
二维数组a几种等价的表述法(表10.1)
名称
几种等价表示形式
二维数组的(首)地址,第0行的地址
&
a,a,a[0]
二维数组第1行的地址
a+1,&
a[1],a[1]
二维数组第0行第1列元素地址
a[0][1],a[0]+1,*(a+0)+1即*a+1
二维数组第1行第2列元素地址
a[1][2],a[1]+2,*(a+1)+2
二维数组第i行第j列元素地址
a[i][j],a[i]+j,*(a+i)+j,
二维数组第i行第j列元素的值
a[i][j],*(a[i]+j),*(*(a+i)+j)
例10.11利用三种不同方式输出一个二维数组的元素
{inta[3][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
inti,j;
3;
i++)//全下标方式
{for(j=0;
j<
j++)
%4d"
a[i][j]);
printf("
\n\n"
for(i=0;
i++)//半下标方式
*(a[i]+j));
i++)//全指针方式
*(*(a+i)+j));
例利用指向数组元素的指针变量输出二维数组的元素
{
inta[3][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int*p;
for(p=a[0];
a[0]+15;
例输出0行0列的地址(分四种不同写法),二维数组各行的首地址
%d,%d,%d\n"
a,&
a,a[0],*a);
a[0],a[1],a[2]);
四、指针与字符串(p232)
1、字符串的表示形式
(1)用字符数组存放一个字符串,如charstring[]="
IloveChina!
"
(2)用字符指针指向一个字符串,如char*s="
CLanguage"
例10.16’
charstring[]="
IloveChina!
//定义一个字符数组
I
l
o
v
\0
C
L
a
n
char*s="
//定义一个字符指针sstring
char*p;
%s\n%s\n"
string,s);
//输出字符串s
*s!
='
\0'
s++)printf("
%c"
*s);
//采用指针输出逐个字符
p=string;
//数组名就是一个字符指针
\n%s\n"
p);
2、字符串指针作为函数参数(P235)
——以字符串复制函数copy_string(f,t)为例(即:
将字符串f复制到字符串t)
(1)用字符数组作为参数
例10.20#include"
voidcopy_string(charf[],chart[])
{inti=0;
while(f[i]!
){t[i]=f[i];
i++;
t[i]='
main()//为了验证copy_string()
chart[20],s[]="
copy_string(s,t);
s,t);
(2)用字符指针作为参数
voidcopy_string(char*f,char*t)
{
while(*f!
){*t=*f;
f++;
t++;
*t='
其中循环语句可以简写:
while((*t=*f)!
){f++;
t++;
进一步简写:
while((*t++=*f++)!
(3)对使用字符指针变量和字符数组的讨论(P238~P241)(自学,略)
五、函数的指针和指向函数的指针变量(P241)
1、用函数指针变量调用函数
可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。
一个函数在编译时被分配给一个人口地址。
这个人口地址就称为函数的指针。
可以用一个指针变量指向函数;
然后通过该指针变量调用此函数先通过一个筒单的例子来回顾一下函数的调用情况。
例10.23求a和b中的大者。
先列出按一般方法的程序。
#include"
{intmax(int,int);
int(*p)();
inta,b,c;
c=max(a,b);
a=%d,b=%d,max=%d\n"
a,b,c);
max(intx,inty)
{intz;
if(x>
y)z=x;
elsez=y;
return(z);
main函数中的“c=max(a,b);
”包括了一次函数调用(调用max函数)。
每一个函数
都占用一段内存单元,它们有一个开始地址。
因此,可以用一个指针函数向一个函数,通
过指针变量来访问它指向的函数。
main函数改写为
main()
int(*p)(int,int);
p=max;
c=(*p)(a,b);
几点说明
(1)~(6)(见P242,略)
2、用指向函数的指针作为函数参数
如:
voidsub(int(*f1)(int,float),float(*f2)(int));
这里表示:
(1)函数sub有两个参数f1和f2,它们都是函数指针;
(2)f1指向的函数返回值为整型,而f2为实型;
(3)f1指向的函数有两个参数,前一个为整型后一个位实型
(4)f2指向的函数有一个整型参数。
应用举例:
求定义在区间[a,b]上函数f(x)的定积分的函数
floatinf(int,int,float(*f2)(float));
六、返回指针值的函数
一般定义为:
类型名*函数名(参数表)
例
{int*max(int,int);
inta,b,*c;
a,b,*c);
int*max(intx,inty)
{int*z;
y)z=&
x;
elsez=&
y;
七、指向数组和指向指针的指针
1、指向数组的指针
一个数组的元素均为指针,则称为指针数组。
指针数组定义方法是:
类型标识符*数组名[数组长度]
例10.27
编写一程序:
先存储一个班的学生的姓名,然后从键盘输入一个姓名,查找该人是否为该班的学生。
string.h"
inti,flag=0;
char*name[5]={"
LiFun"
"
ZhangLi"
LingMaoTi"
SunFei"
WangBao"
};
//定义指针数组
charyour_name[20];
Enteryourname:
gets(your_name);
i++)if(strcmp(name[i],your_name)==0)flag=1;
puts(your_name);
if(flag==1)
isinthisclass.\n"
else
isnotinthisclass.\n"
2、指向指针的指针
指针变量可以指向各种数据,包括指针,指向指针类型的变量称为指向指针的指针,又称为二级(重)指针,
其类型定义方法是:
(类型名)**(指针变量名)
例10.28inti=314,*p1,**p2;
p2p1i
314
p2=&
p1;
ip1p2
printf(“%d,%d,%d\n”,i,*p1,**p2);
因为i,*p1,**p2表示同一个变量,所以输出的结果是314,314,314。
八、有关指针的数据类型和指针运算小结(P255)
1、有关指针的数据类型小结
定义
含义
inti;
int*p;
inta[10];
int*a[10]
int(*p)[10]
intf()
int*p()
int(*p)()
int**p
2、指针运算小结
(1)~
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第8章 指针
![提示](https://static.bdocx.com/images/bang_tan.gif)