C语言指针Word文档下载推荐.docx
- 文档编号:20534312
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:38
- 大小:43.86KB
C语言指针Word文档下载推荐.docx
《C语言指针Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《C语言指针Word文档下载推荐.docx(38页珍藏版)》请在冰豆网上搜索。
指针类型与其他数据类型一样,也有相应的变量——指针变量。
指针变量是用来存放其他对象的内存地址。
如:
int*p=&
a;
p为指针变量,用来存放变量a对应的内存单元的地址。
对于a的存单元,既可以用变量名a访问,也可以用指针p来实现访问:
*p
此时*p和a的值一样,即p中存放a的地址,而*p代表a。
注意:
●
int*p=&
中“*”相当于一特殊类型说明符,说明p是指针型变量。
在定义p的同时,将系统为a所分配单元的地址赋给p(而不是给*p),在程序的其他地方只能用p=&
要区分指针与指针变量的概念:
指针是一地址码,为数据对象所分存储空间的首地址;
而指针变量是一个数据对象,需要分配存储单元,其中存放的是地址码(即指针),并且只能存放地址,不能存放其他数据。
第二节指针变量的使用
一、指针变量的定义及赋值
指针变量与其他变量一样,都是变量,都需要通过定义来分配存储单元,然后才能使用。
当然也可以在定义的同时进行初始化。
指针变量定义的一般形式为:
基类型*
指针变量名;
例如:
int*p;
表示定义一个指针变量p。
定义中的“*”表示该变量为一个指针变量而不是其他类型的变量,而前面的基类型,不是指针变量p所存放的类型,而是p的值所指向变量的数据类型,如上例中,p所存放的指针所指向的类型为int。
在定义中的“*”虽和前面所介绍的类型标识符有同样的功能,但只对一个变量名有效,如果要定义多个指针变量,需要多个“*”。
int*p1,p2,*p3;
表示定义了两个指针变量p1和p3,而p2为一整型变量。
在定义指针变量的同时,也可以初始化,其初值为基类型变量的地址。
inta;
*pa=&
在定义指针变量pa的同时将整型变量a的地址赋值给它。
✍
要求在赋初值时,初值对应的变量必须先定义。
上例可以写成:
inta,*pa=&
但不能写成:
int*pa=&
a,a;
要求初值对应变量的类型要与基类型相同。
即一个指针变量只能指向同一种类型的变量。
float*p=&
这种初始化是错误的。
对指针变量初始化时,只能给他赋地址,而不能是其他类型的数据。
虽然地址是存储单元的地址码,是整数,但一般不能将整数作为初值。
因为程序中变量的地址只能由编译程序分配而不能人为指定。
int
*p=1000;
/*错误赋值*/
但可以将0赋值给指针变量,表示该指针未指向任何对象,为空指针。
float*fp=0;
/*表示fp未指向任何float对象*/
与其他变量一样,指针变量除了初始化赋值之外,还可以在定义之后给它赋值,让它指向一个对象。
a,*p;
p=&
二、
指针的类型
对于不同的数据类型,其对象在内存中要占用不同数目的存储单元,并且其运行方法也完全不同。
如在TurboC下,int类型数据占2byte,float类型数据占4byte,他们的运算一种是整型运算,一种是浮点运算。
但对于指针变量来说,不管它指向的是什么类型的对象,他们的值都是地址,因而都占有相同数目的单元,在TurboC为2byte。
通过指针变量可以访问所指向的对象,进行操作与运算。
由于不同类型的数据占用的单元数不一样,进行的运算也不相同,因而也要对指向它们的指针变量进行区别,即指针变量也有类型。
指针变量的类型就是它所指向对象的类型。
doube
d=3.5;
double*dp=&
d;
/*dp为一个double类型的指针变量*/
一个指针变量要有相应类型,并且只能指向同一类型,如dp只能指向double类型的变量,而不能指向其他类型的变量。
要区分开指针变量的值和指针变量所指向变量的值。
如上例中,指针变量dp的值为变量d的地址,所指向变量的值为d的值,即为3.5。
三、
指针运算符
C语言提供了两种指针运算符:
取地址运算符(&
)和引用目标运算符(*)。
1.取地址运算符(&
)
取地址运算符是单目运算符,其结合性为从右→左,其功能是取变量的地址,使用格式为:
&
左值
左值是具有内存单元的数据,如变量、数组元素及结构变量和联合中的数据成员都是左值,可以用“&
”运算符取得它们的地址,因而&
左值是一个指针表达式,可以用它来作为指针变量的值。
要区分开取地址运算符&
与双目运算符&
(按位与)。
2.引用目标运算符(*)
与取地址运算符“&
”相对应的是引用目标运算符“*”。
该运算符也是单目运算符,结合性为从右→左,这种运算符只能作用在指针表达式的数据上。
其使用格式为:
*指针表达式
功能:
“*”运算符形成的表达式表示指针表达式所指向的对象,通过它可以完成对该对象的访问:
读和写。
例8.2
分析下面程序运行结果。
main(
)
{
n,*pi;
d,*pd;
pi=&
n;
pd=&
printf("
pleaseinputnandd:
"
);
scanf("
%d%lf"
pi,pd);
n=%d,*pi=%d\n"
n,*pi);
d=%f,*pd=%f\n"
d,*pd);
}
程序运行结果为:
23
76.8↙
n=23,*pi=23
d=76.800000,*pd=76.800000
通过scanf()函数中使用pi、pd实现对指向对象的赋值。
在printf()函数中通过*pi、*pd实现对变量n和d的输出(即变量的读操作)。
也可以在一个语句中同实现对指向对象的读和写操作,如:
n=10,*pi=&
(*p)++;
首先通过*p取出变量n的值作为表达式的值,然后再将该值加1之后,又赋值给变量n。
在对指针变量使用“*”运算符时,要求指针变量已经指向了一个确定的对象。
也即对指针变量必须先赋值,再使用“*”运算符。
(*p)++和*p++之间的关系:
(*p)++表示对p所指向的对象加1修改,p仍指向原来的对象;
而*p++表示先通过p去访问所指向的对象,再让p指向下一个对象,它等价于*(p++);
几个等价关系:
假设有int
a,
*p=&
则有如下等价关系:
①
*p与a等价,等价于*&
a;
②
p与&
a等价,等价于&
*p;
例8.3
分析下面程序的运行结果:
a=10,
b=20;
int*pa,*pb,*p;
pa=&
a,pb=&
b;
a=%d,b=%d,*pa=%d,*pb=%d\n"
a,b,*pa,*pb);
p=pa;
pa=pb;
pb=p;
a=%d,b=%d,*pa=%d,*pb=%d\n"
a,b,*pa,*pb);
运行结果为:
a=10,b=20,*pa=10,*pb=20
a=10,b=20,*pa=20,*pb=10
指针值的变化过程如图8.2。
说明:
图中的“
”表示指针值所指向的对象,“
”表示存储单元之间值的拷贝,本章所有图形中的这两种箭头均表示相同意思。
例8.4
分析下面程序的运行结果。
main(
)
{
a=10,b=20,t;
int*pa,*pb;
printf("
b,*pa,*pb);
t=*pa,*pa=*pb,*pb=t;
运行结果为:
a=10,b=20,*pa=10,*pb=20
a=20,b=10,*pa=20,*pb=10
通过指针交换所指对象的过程如图8.3。
四、指针常量
同其他类型一样,有变量就有常量。
在C语言中,指针常量有:
数组名、函数名、字符串常量等。
数组名代表该数组在内存中分配的存储区的首地址,指向数组中的第一个元素,实际上就是指针类型的数据。
由于数组分配空间之后面,直到其生命期结束之前不会重新分配空间,因而数组名为指针常量。
函数代码存放在代码区,在程序的整个运行期,它不会改变,而函数名正好代表函数在代码区的首地址,因而函数名也是指针常量。
a[100],*p;
a就代表数组的首地址,指向第一个元素a[0],而p为一般的指针变量。
对于数组名a和一般的指针变量p它们的区别:
a是指针常量,不能修改它的值,它总是代表数组的首地址;
而p为变量,可以重新赋值,即让它指向不同的对象。
a的意义是代表一个能存放100个int类型的存储区;
而p在赋值之前,未指向任何有意义的单元。
第三节
指针与数组
在C语言中指针与数组的关系非常密切。
一、
指针与数组名之间的关系
前面已经介绍过数组名代表整个数组空间的首地址,指向的是数组中的第一个元素,而指针也是地址,因此数组名与指针都具有完全相同的数据类型,这使得他们的运算都具有通用性。
对数组元素的访问,是通过数组名利用下标运算符“[]”来实现访问,即:
数组名[下标]
可以转化为:
地址[整数]
也即:
(指针表达式)[整数]
例8.5
#define
N
5
a[N],*p,i;
for(i=0;
i<
N;
i++)
a[i]=i+10;
p=a;
for(i=0;
i++)
%5d"
a[i]);
\n"
p[i]);
10
11
12
13
14
13
14
由上例可知:
a[i]等价于p[i],说明指针变量也可以用下标方式来访问对应单元中的值。
定义指向数组元素的指针变量
定义指向数组元素的指针变量与指向简单变量的指针变量完全一样。
首先定义与数组元素类型一致的指针变量,然后再将数组元素的地址赋给指针变量,最后通过指针变量来引用数组元素。
例8.6
#define
inta[N],*p,i;
a[i];
*p=i*2;
*p);
0
2
4
6
8
通过指针引用数组元素实现了对数组元素的读和写操作。
指针的运算
指针是一种特殊的类型,它是以指针变量所持有的地址作为运算对象进行运算。
除了前面介绍的“*”和“&
”可以使用,还有指针的加、减、比较等运算,而这些运算主要与数组操作相关。
1.指针与整数的加减运算
一个指针可以加上或减去一个整数,包括加1、减1。
前面介绍的数组元素访问方式为:
a[i],C语言中,实际上是先将a[i]转换成*(a+i)的形式然后再去求值。
这表明a+i是数组中第i+1个元素的地址,i为数组元素a[i]相对于a[0]的偏移量。
一个地址加减上一个整数其结果仍为地址,并且加减的单位不是以字节为单位,而是以指向的数据类型所占用的字节数为单位。
如int指针,以2byte为单位,double指针,以8byte为单位。
因此,p+n表示的实际地址为(假设p指针的基类型为type):
p+n*sizeof(type)
例8.7
a[10]={1,2,3,4,5,6,7,8,9,10};
*p=a;
ais:
%X,a+3is:
%X\n"
a,a+3);
pis:
%X,p+3is:
p,p+3);
*ais:
%d,*(a+3)is:
%d\n"
*a,*(a+3));
*pis:
%d,*(p+3)is:
*p,*(p+3));
p[0]is:
%d,p[3]is:
p[0],p[3]);
FFC8,a+3is:
FFCE
(结果有可能不相同)
FFC8,p+3is:
FFCE
1,*(a+3)is:
4
1,*(p+3)is:
1,p[3]is:
由运行结果可见:
a+i等价于p+i,同时还有:
*(a+i)等价于*(p+i),并且等价于a[i]和p[i]。
对p++、p--也是以基类型占用的存储单元进行,同时要修改p本身的值,让p指向后一个或前一个数据。
2.
指针之间的减运算
一般是同类型指针之间进行减运算。
对同类型的指针p、q,p-q表示p与q所指对象之间的元素个数。
例8.8
d[5];
*p,*q;
p=d,
q=d+4;
p:
%X,q:
%X,q-p:
p,q,q-p);
运行结果:
p:
FFB0,q:
FFD0,q-p:
由结果可知:
两指针相减并不是两指针值之差,而是两指针所指对象之间的元素个数,所以实际值为指向type类型的两指针p和q之间的的差为:
(q-p)/sizeof(type)
3.指针之间的关系运算
指针之间的关系运算主要用在同类型的指针之间,用来表示两指针所指对象之间的前后关系。
可以使用所有的关系运算符。
例8.9
将数组中的元素按位置颠倒。
分析:
可由两个指针p和q分别指向数组的两端,p和q分别向中间移动,同时交换它们所指向的值,停止交换的条件是:
p≥q。
(8-3.1)中的
符号表示交换,p=a,q=a+N-1对应赋值复句,下面部分对应一while型循环语句,循环头为:
while(p<
q)。
程序如下:
10
a[N]={1,2,3,4,5,6,7,8,9,10};
*p,*q,t;
p=a,q=a+N-1;
while(p<
q)
t=*p;
*p++=*q;
*q--=t;
p=a,q=a+N;
theitemsof
array
are:
\n"
*p++);
the
itemsofarrayare:
10
9
8
7
5
4
3
1
(*p)++和*p++之间的关系:
*p++根据运算符的优先级和结合性,先计算表达式p++的值,其值为p原来所指向变量的地址,然后p指向下一个单元,最后再“*”运算符作用于表达式p++的值,取出p原来所指向的对象的值。
它们的区别为:
(*p)++改变的是p所指向对象的值,整个表达式的值为p所指向对象值加1;
而*p++改变的是指针p的值,整个表达式的值为p原来所指对象的值。
*(p++)、*++p和*p++:
都要修改p的值;
实际上*(p++)与*p++是等价的,都是先取出p所指对象的值,再修改p的值;
而*++p先修改p的值,再取出p当前所指向的对象的值。
为了增加可读性,建议使用*(p++)和*(++p)。
实际上(8-3.1)是等价于:
而
对应一个for型循环语句:
i<
N/2;
i++)
t=a[i],a[i]=a[N-i-1],a[N-i-1]=t;
加上说明和输入输出则可以编出另一程序,这里程序略。
四、
指针与一维数组
假设有:
a[N],
a[0],
*q=&
a[N-1];
用指针来引用一维数组的元素,主要有以下方法:
偏移量法:
用指针加上偏移量,形如*(p+i)或p[i],表示数组a的第i个元素a[i];
修改指针变量p或q的值,让他们依次指向数组中的每一个元素,一般形式为:
*p++,*q--。
将数组名用作指针,利用偏移量法:
*(a+i)或a[i]。
例8.10
求字符串的长度。
若p存放字符串的首地址,q存放字符串结束字符的地址,则字符串的长度为:
len=q-p;
c[10]="
abcde"
;
char*p=c,
*q=p;
len;
while(*q!
='
\0'
q++;
len=q-p;
thelenof
string
is:
len);
thelenof
5
例8.11
将数组中的元素先从中间向前输出前半部分的元素,然后再从中间向后输出后半部分的元素。
首先要确定数组中间位置的元素下标,假设数组的长度为N,则可定中间元素的下标为(注意数组的下标从0开始):
,再分两步完成输出操作。
int*p,*q,
m,
i;
m=(N-1)/2;
/*利用指针偏移量方式*/
i=m;
while(i>
=0)
*(p+i));
i--;
}
i=m+1;
while(i<
N)
i++;
1
思考:
该程序是通过指针偏移量来实现的,请问如何通过指针下标方式、指针增量方式、数组名偏移量方式实现?
在用指针变量引用数组元素时,一定要注意是否越界(即超出数组的范围)。
五、
指针与二维数组
通过指针来引用二维数组中的元素要比处理一维数组复杂得多。
前面已经介绍二维数组在内存中的存放方式:
由于内存单元的组织是以线性结构组织的,因此二维数组也是以线形方式组织,并且以行序为主序进行处理。
虽然他与一维数组的存放形式一样
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 指针