高级语言程序设计-从C到C++(第二版)课件:指针_第1页
高级语言程序设计-从C到C++(第二版)课件:指针_第2页
高级语言程序设计-从C到C++(第二版)课件:指针_第3页
高级语言程序设计-从C到C++(第二版)课件:指针_第4页
高级语言程序设计-从C到C++(第二版)课件:指针_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

7.1指针的概念7.2指针变量7.3指针与一维数组7.4指针与多维数组7.5指针与字符串7.1指针的概念程序中的每条指令或数据都需要存放在计算机的存储器中,在编译或运行程序的过程中为它们分配内存单元。内存单元以字节为单位,每一个字节对应一个地址。对象(如变量、数组、函数等)的地址是指该对象所占存储单元的首个字节的编号,而对象名作为一个标识符,是用来标注该对象的。标识符的使用是为了方便程序的编写。系统在引用对象时,是通过地址找到该对象,再根据对象的类型在相应长度的存储单元中存取数据。由于通过地址可以找到相应的对象,即地址指向该对象,因此地址也被称为“指针”。换句话说,指针就是地址。对象的指针就是该对象所在存储单元的首字节地址。7.2指针变量指针变量是专门用来存放地址的变量。通过指针变量来存放某一特定变量的地址,可以建立指针变量与其指向变量之间的关联。为了表示指针变量和它所指向的变量之间的联系,在程序中使用指针运算符“*”表示“指向”。变量名与变量的地址之间存在映射关系。在程序设计过程中,为了方便对变量的引用而使用变量名;在程序运行过程中,系统对变量的访问使用的是地址;程序经过编译后,变量名会转换为变量的地址。通过变量名访问变量的方式称为“直接访问”。之前我们一直都是使用“直接访问”的方式引用变量的。指针变量可以用来存放某一特定变量的地址。通过指针变量获取地址从而访问该地址所对应的变量,称为“间接访问”,如图7-1所示。图中的箭头表示“指向”关系。int型变量a的值为5,a的地址为2000;现定义指向int型变量的指针变量p,用于存放int型变量a的地址,即p=&a,值为2000;而*p就表示指针变量p所指向的int型变量a,即*p=a。在通过指针实现对变量的间接访问时,系统首先根据存放于变量p中的地址2000,找到变量a所在存储单元的起始位置,并根据int型数据所占空间大小,将从地址2000开始到2003结束的4个字节存储单元中的数据取出,即整数5。通过“间接访问”的方式引用变量,可以大大提高程序的执行效率并使程序更加简洁。在深入介绍指针之前,我们先理顺以下几个概念:(1)地址:内存中存储单元的编号。

(2)变量:内存中某个特定的存储单元。(3)变量的地址:某一变量所在的存储单元的地址编号。

(4)变量的名称:为该存储单元所定义的名称,便于程序设计。(5)变量的值:存放在特定存储单元中的数据。(6)指针:地址。(7)变量的指针:变量的地址。(8)指针变量:存放地址的变量。(9)指向变量的指针变量:存放某个特定变量地址的指针变量,通过该指针变量可以指向特定的变量。7.2.1指针变量的定义指针变量是专门用来存放地址的变量,变量的类型为“指针”类型。定义指针变量的基本格式为“指针变量名”是定义的指针变量的标识符。“*”是类型符,与“char”、“int”、“float”的作用相同,表示定义的变量为指针类型。“类型”用于声明定义的指针变量所指向的变量的类型。7.2.2指针变量的赋值定义指针变量后,如果没有对其赋值,那么该指针变量的值是不确定的,即不能确定指针变量中当前存放的是哪个内存单元的地址。此时如果盲目访问,可能会破坏内存中原有的重要数据或程序代码。因此,对于指针变量,应该先赋值、再引用。使用指针变量存放内存中任意一个地址是没有意义并且危险的。虽然地址是以整数形式表示的,但不要将一个整数赋值给指针变量,因为并不清楚该整数表示的地址中存放的是什么数据。正确的方法是用一个已知存在的变量地址为指针变量赋值。7.2.3指针变量的引用C语言标准提供了两种运算符来引用指针:(1)“&”,取地址运算符,如“&a”为变量a的地址。(2)“*”,指针运算符,如“*p”为指针变量p所指向的变量。7.2.4指针变量的运算指针变量的算术运算其实就是地址的算术运算。C语言允许指针与一个整数进行加减运算,以实现移动指针的目的。以“inta=1,*p=&a;(设a的地址为2004)”为例,通过之前的学习,我们已经知道:指针变量p存储的是变量a的地址,即p=&a,值为2004。*p表示指针变量p所指向的变量a,即 *p=a,值为1。(1)“&”和“*”同为单目运算符,优先级相同,结合性自右向左,所以,&*p表示指针p所指向的变量的地址,即&*p=&(*p)=&a,值为2004。而 *&a表示变量a的地址所指向的变量,即 *&a=*(&a)=*p,值为1。(2)指针变量可以作自增自减运算,++p或p++,表示p的值加1。由于p存放的是地址,所以此处的加“1”表示移动一个基类型的数据长度单位;由于变量p的基类型是int类型,数据长度单位为4个字节,所以当 ++p或p++ 作为一个独立、完整的表达式时,其存储的地址均更新为2004 + 4 = 2008。(3)指针所指向的变量作自增自减运算,--(*p) 或 (*p)--,表示指针p所指向的变量的值减1,由于变量a的值为1,所以,当 --(*p)或(*p)-- 作为一个独立、完整的表达式时,其指向的变量a的值均为1-1 = 0。(4)自增自减运算符“++”、“--”和“*”同为单目运算符,优先级相同,结合性都是自右向左,所以在两种运算符同时使用的场合,为避免混淆,应使用括号进行区分。(5)针对指针变量的加减运算,应确认在运算后该指针变量的指向关系,避免运算后指向未知的内存空间。7.2.5使用指针变量作函数参数使用基本类型变量作函数参数是“单向的值传递”,形参的值在被调函数中发生改变,不会影响到主调函数中的实参。并且,当主调函数需要获取被调函数的运行结果时,必须使用return语句,而每调用一次被调函数,只能执行一条return语句,并且每条return语句只能返回一个值。使用指向变量的指针作函数实参,将主调函数中实参的地址传递给形参,则形参与实参共用该实参变量所指向的内存空间。在被调函数中改变形参所指向的变量的值,实际上就是改变主调函数中实参变量所指向的变量的值。所以,从这个角度来看,“指针传递”带来的影响是“双向的”。同时,可以看出,主调函数中变量值的改变,并不需要通过执行return语句来实现。这种方式,又叫做地址传递(传地址)或者引用传递(传引用)。主函数在调用square函数时,将实参的地址传递给square函数的形参,建立了形参到实参的指向关系,可以认为该指向关系的建立是通过“int*n=&inumber;”形式实现的。square函数中对指针变量n所做的处理由于指向关系的存在,实际修改的是主函数中变量inumber的值。square函数调用结束后,形参到实参的指向关系结束。7.3指针与一维数组指针既然可以指向变量,当然也可以指向数组元素。数组是同类型数据的有序集合,数组名就是数组的首元素的地址。通过对指向数组元素的指针做加减运算,可以很方便地获取数组中任意一个元素的地址。指针做加减运算的特点,使得指针特别适合处理像数组这样存储在连续内存空间中的数据。对数组元素的引用,可以使用下标来实现,也可以借助指针来实现,即通过指向数组元素的指针找到需要引用的元素。使用指针访问数组元素,能使目标程序所占内存更少,运行速度更快。7.3.1指向数组元素的指针为了实现借助指针引用数组元素,通常将数组的首元素的地址赋值给与数组类型相同的指针变量,建立指针变量到该数组首元素的指向关系,并通过执行指针的加减运算,将指针指向数组中的各个元素,其关系如图7-2所示。 将数组名赋值给指针变量:将数组首个元素的地址赋值给指针变量:以图7-2为例,当指针p指向数组a的首字节地址时,则建立如下的等价关系:同样以图7-2为例,若指针p指向数组a的第i个元素,则得到如下的等价关系:其中,指针变量结合自增或自减运算符,可以使指针自动向后或向前移动,直接指向下一个或上一个数组元素,而不必每次都重新计算地址。这种有规律地改变地址值的做法可以大大提高程序的执行效率。但是需要注意对数组元素的引用不能越界。在引用数组元素时,可以使用两种方法:下标法和指针法。7.3.2指向数组元素的指针作函数参数将指向数组元素的指针作为实参传递给被调函数的形参,可以在被调函数中通过形参指针直接改变主调函数中的数组元素。实参可以是数组名,也可以是指向数组元素的指针变量;形参需要接收数组元素的地址,所以必须是指针变量且其类型与数组的类型一致。【例7.8】通过指针传递,在被调函数中将数组元素的值翻倍。运行结果:在main函数中定义指针变量pm,并使用数组a的地址对指针变量pm进行了初始化,建立指针pm到数组a的首元素的指向关系。对数组元素的存取采用了指针方式,即“*(pm++)”,当然也可以采用下标法“a[i]”,或者“*(a+i)”和“*(pm+i)”的指针形式,但不能写成“*(a++)”的形式,因为a是指针常量。在调用change函数前,以“*(pm++)”方式通过循环结构逐一输出数组元素,在结束循环之后,指针pm已经越过了数组的界限而指向其后的4字节存储单元;此时应将pm重新赋值为数组a的首元素地址,让指针pm再次指向数组a,以保证在此之后,使用指针传递正确的地址。在调用change函数时,将元素个数和数组地址分别传递给了change函数的形参变量n和形参指针pc,表达式“change(4,pm)”可以改写为“change(4,a)”、“change(4,&a[0])”。在change函数中执行循环语句,先将指针pc所指向的变量的值更新为原值的2倍,再通过pc的自增,将指针指向下一个元素。表达式“*pc++”表示先引用指针pc所指向的变量,再对pc(地址)的值自增,而不是直接对 *pc(指向的变量)的值自增。在change函数中并没有通过return语句向main函数返回数据,但由于在函数调用时,传递的是数组地址,因此在change函数中通过改变形参指针直接影响了main函数中的数组元素。7.4指针与多维数组多维数组也是同一类型数据的有序集合,其存储形式与一维数组的存储形式相同,即所有元素按顺序占用一段连续的内存空间。通过前面的介绍,我们已掌握通过指针引用一维数组元素的方法。本节以二维数组为例,介绍通过指针引用多维数组元素的方法。7.4.1通过指针引用二维数组元素通过对指向数组元素的指针做加减运算,可以很方便地存取一维数组中任意一个元素。二维数组的存储形式与一维数组的存储形式相同,也是将所有的元素按顺序存放在一段连续的内存空间中,所以也可以建立指针与二维数组的关系,以便引用二维数组元素。【例7.11】使用指针引用二维数组元素。运行结果:程序中定义了一个类型为int型的指针变量p,并使用数组名a初始化,建立指针p到二维数组的指向关系。由于二维数组在内存中的存储是行优先,即按行的顺序连续存储,“inta[3][4]”表示二维数组a有3行,每行有4个元素,共有12(3行 × 4列)个元素。程序中以变量i表示元素的行下标、变量j表示元素的列下标,则有表达式“(p+i*4+j)”表示在二维数组第i行上的第j个元素的地址,输出参数“*(p+i*4+j)”即表示该地址所指向的元素。在循环语句的控制下,指针p从指向二维数组a的首个元素开始,按照存储顺序,逐一指向数组中的各个元素。当然如果把二维数组当作一维数组来处理,程序中的循环语句也可以改为7.4.2指向数组的指针严格来说,C语言并没有“多维数组”这一概念,程序设计人员所说的“多维数组”,C语言将其描述为“数组的数组”。因此,对于多维数组,C语言并不像处理一维数组那样,简单地将其转换为指向同类型变量的指针,而是将其转换为指向同类型数组的指针。数组是一个可以递归的概念:任何维数的数组都可以看作由比它少一维的数组作为元素组成的“一维”数组。C语言总是将多维数组转换成一维数组来处理的,如果该一维数组的元素又是一个一维数组或多维数组,则根据递归定义,再次转换,直到转换后的一维数组元素为基本类型变量为止。这就是C语言描述的“数组的数组”的含义。C语言在处理一维数组时,将其转换为指向同类型变量的指针。在处理多维数组时,将其转换为指向同类型数组的指针。7.4.3指向数组的指针作函数参数只要能保证引用表达式的正确,无论是通过指向数组元素的指针还是通过指向数组的指针,都可以引用二维数组元素。然而,使用指向数组的指针引用二维数组元素,能够更加便捷地访问二维数组中特定一行的数据,并且在语义上更能体现程序设计的思想。7.5指针与字符串类型为char型的指针变量,也称为字符指针。字符指针可以指向一个字符变量,也可以指向一个字符数组。C语言没有字符串数据类型,而是将字符串作为字符数组来处理,以“\0”作为字符串的结束标记。对于通过指针引用字符和字符数组,与前面的内容并无区别。7.5.1字符串的引用形式在引用一个字符串时,可以采用以下两种方式:(1)定义一个字符数组,将字符串存入该数组。使用字符串常量初始化字符数组,从数组的首地址开始,依次将字符串中的字符逐一写入存储单元,并自动存入一个“\0”作为结束符。对于该字符串的引用,可以采用数组的下标,也可以使用%s控制符读取。(2)定义一个字符指针,建立对字符串常量的指向关系。通过定义一个字符指针并以字符串常量对该指针进行初始化,建立了指向关系。这个指向关系的建立,是通过把字符串的首元素赋值给了类型为char型的指针变量string来实现的,因此可以通过该指针变量逐一存取字符串,当然也可以通过%s控制符读取。7.5.2指向字符串的指针在使用字符指针引用字符串时,需注意以下几个问题:(1)字符指针对字符串的引用。定义字符指针时可以使用字符串进行初始化;定义字符指针后,使用字符串首字符的地址为字符指针赋值,从而建立指向关系。在指向关系的建立过程中,系统并不是用字符串“hello

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论