C指针详解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第6章指针
指针是C 语言的精华部分,通过利用指针,我们能很好地利用内存资源,使其发挥最大的效率。有了指针技术,我们可以描述复杂的数据结构,对字符串的处理可以更灵活,对数组的处理更方便,使程序的书写简洁,高效,清爽。但由于指针对初学者来说,难于理解和掌握,需要一定的计算机硬件的知识做基础,这就需要多做多练,多上机动手,才能在实践中尽快掌握,成为C 的高手。
6.1 指针与指针变量过去,我们在编程中定义或说明变量,编译系统就为已定义的变量分配相应的内存单元,也就是说,每个变量在内存会有固定的位置,有具体的地址。由于变量的数据类型不同,它所占的内存单元数也不相同。若我们在程序中做定义为:
int a=1,b=2;
float x=3.4,y = 4 . 5
;double m=3.124;char ch1='a',ch2='b';
让我们先看一下编译系统是怎样为变量分配内存的。变量a ,b 是整型变量,在内存各占2个字节;x ,y 是实型,各占4个字节;m 是双精度实型,占8个字节;c h 1,c h 2是字符型,各占1个字节。由于计算机内存是按字节编址的,设变量的存放从内存2 000单元开始存放,则编译系统对变量在内存的安放情况为图6 -1所示。
变量在内存中按照数据类型的不同,占内存的
大小也不同,都有具体的内存单元地址,如变量 a 在内存的地址是2 000,占据两个字节后,变量b 的内存地址就为2 0 0 2,变量m 的内存地址为2 0 1 2等。对内存中变量的访问,过去用scanf("%d%d%f",&a,&b,&x) 表示将数据输入变量的地址所指示的内存单元。那么,访问变量,首先应找到其在内存的地址,或者说,一个地址唯一指向一个内存变量,我们称这个地址为变量的指针。如果将变量的地址保存在内存的特定区域,用变量来存放这些地址,这样的变量就是指针变量,通过指针对所指向变量的访问,也就是一种对变量的“间接访问”。
设一组指针变量p a 、p b 、p x 、p y 、p m 、p c h 1、p c h 2,分别指向上述的变量a 、b 、x 、y 、m 、c h 1、c h 2,指针变量也同样被存放在内存,二者的关系如图6 -2所示:
在图6 -2中,左部所示的内存存放了指针变量的值,该值给出的是所指变量的地址,通过该地址,就可以对右部描述的变量进行访问。如指针变量p a 的值为2 000,是变量a 在内存的地
变量a 变量b 变量x
变量y
变量m
1200020022004
2008201220202021
23.4
4.5
3.124a b
变量ch1变量ch2
图6-1 不同数据类型的变量在内存中
占用的空间
址。因此,p a 就指向变量a 。变量的地址就是指针,存放指针的变量就是指针变量。
图6-2 指针变量与变量在内存中的关系
6.2 指针变量的定义与引用
6.2.1 指针变量的定义
在C 程序中,存放地址的指针变量需专门定义;
int *ptr1;float *ptr2;char *ptr3;
表示定义了三个指针变量p t r 1、p t r 2、p t r 3。p t r 1可以指向一个整型变量,p t r 2可以指向一个实型变量,p t r 3可以指向一个字符型变量,换句话说,p t r 1、p t r 2、p t r 3可以分别存放整型变量的地址、实型变量的地址、字符型变量的地址。
定义了指针变量,我们才可以写入指向某种数据类型的变量的地址,或者说是为指针变量赋初值:
int *ptr1,m= 3;
float *ptr2, f=4.5;char *ptr3, ch='a';p t r 1 = & m
;p
t r 2=&f ;p t r 3=&c h ;
上述赋值语句p t r 1=&m 表示将变量m 的地址赋给指针变量p t r 1,此时p t r 1就指向m 。三条赋值语句产生的效果是p t r 1指向m ;p t r 2指向f ;p t r 3指向ch 。用示意图6 -3描述如下:
pa pb px py pm
pch1pch2
2000
2002
2004
2008
2012
20202021
2000200220042008201220202021
1
23.44.5
3.124a b
100010021004100610081010101210141016
变量a 变量b 变量x
变量y
变量m
变量ch1变量ch2
*p2
return 0;
}
void chang(int *pt1,int *pt2)
{/*子程序实现将两数值调整为由大到小*/
int t;
if (*pt1<*pt2)/*交换内存变量的值*/
{
t=*pt1; *pt1=*pt2;*p t2=t;}
r e t u r n;
}
由于在调用子程序时,实际参数是指针变量,形式参数也是指针变量,实参与形参相结合,传值调用将指针变量传递给形式参数p t1和p t2。但此时传值传递的是变量地址,使得在子程序中p t1和p t2具有了p 1和p 2的值,指向了与调用程序相同的内存变量,并对其在内存存放的数据进行了交换,其效果与[例6 -2]相同。
思考下面的程序,是否也能达到相同的效果呢?
m a i n()
{
void chang();
int *p1,*p2,a,b,*t;
s c a n f("%d,%d",&a,&b);
p1=&a;
p2=&b;
c h a n g(p1,p2);
p r i n t f("%d,%d\n",*p1,*p2);
}
void chang(int *pt1,int *pt2)
{
int *t;
if (*pt1<*pt2)
{
t=pt1; pt1=pt2;p t2=t;
}
r e t u r n;
}
程序运行结束,并未达到预期的结果,输出与输入完全相同。其原因是对子程序来说,函数内部进行指针相互交换指向,而在内存存放的数据并未移动,子程序调用结束后,
m a i n()函数中p 1和p 2保持原指向,结果与输入相同。
6.4 指针与数组
变量在内存存放是有地址的,数组在内存存放也同样具有地址。对数组来说,数组名就是数组在内存安放的首地址。指针变量是用于存放变量的地址,可以指向变量,当然也可存放数组的首址或数组元素的地址,这就是说,指针变量可以指向数组或数组元素,对数组而言,数组和数组元素的引用,也同样可以使用指针变量。下面就分别介绍指针与不同类型的数组。