轻松学C之指针与引用_第1页
轻松学C之指针与引用_第2页
轻松学C之指针与引用_第3页
轻松学C之指针与引用_第4页
轻松学C之指针与引用_第5页
已阅读5页,还剩107页未读 继续免费阅读

下载本文档

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

文档简介

1、第7章 指针与引用指针和引用被认为是C+中的特殊数据类型,它与前面章节介绍的基本数据类型不同。使用指针和引用可使程序简洁、紧凑和高效,所以对于每一个学习C+语言的人,都要掌握指针和引用的使用方法。指针和引用的用法比较特殊,而且运用非常灵活。本章将详细讲述指针和引用的概念和使用。7.1 指针概述计算机的数据都是存储在内存中,内存是按字节排列的存储空间,每个字节都有一个编号,被称为地址,程序中用到的数据和声明的变量都存放在这一个个字节中,不同类型的数据和变量占用的字节字数不同,习惯上将某个变量占用的字节数称为内存单元,指针就是记录这些地址的变量,而指针的类型表示指针指向地址存储的数据类型。准确地理

2、解指针的概念是掌握指针的前提。 7.1.1 指针的基本概念简单地说,指针是一个地址,它指向存储某一个数据的存储地址。此外,还有一个指针变量的概念如图7-1所示。图7-1 指针变量及其访问方法在现实生活中,指针的概念也是比较常见的。例如,高速公路上的交通指示牌指示了某地的地理位置,这就是指针,而这个指示牌就是指针变量,用于存储指针,如图7-2所示。图7-2 指针的概念在C+中,如果在内存中存储了一个变量a,其值为100,那么用通过指针变量p访问该变量的流程如图7-3所示。图7-3 指针可以看到,指针变量p指向变量a。在理解“指向”的时候,应该了解指针变量p中存有变量a的地址,通过该地址就能找到变

3、量a。因此,在C+语言中用指针来表示指向关系,即指针就是地址。注意:在C+具体程序中参加数据处理的量不是指针本身的量,而是指针所指向的变量,即指针所指向的内存区域中的数据(称为指针的目标)才是需要处理的数据。7.1.2 定义指针变量指针是一种复合型的数据类型,基于该类型声明的变量称为指针变量,该变量存放在内存中的某个地址,与其他基本数据类型一样,使用指针之前也必须先定义指针变量。在C+中,定义指针变量的一般形式如图7-4所示。图7-4 定义指针变量的一般形式需要注意的是,定义一个指针变量必须用符号“*”,它表明其后的变量是指针变量,但不要认为“*p”是指针变量,指针变量是p而不是*p。此外,有

4、相同存储类型和数据类型的指针可以在一行中说明,也可以和同类型的普通变量在一起说明,如图7-5所示。图7-5 指针变量的说明当在一行中定义多个同一类型的指针时,用逗号隔开各指针变量标识符,并且每个变量前都要加上“*”。否则该变量就不是一个指针,而是一个普通类型的变量。如图7-6中定义的变量语句。图7-6 不加“*”含义不同注意:定义指针变量时,“*”可以出现在类型名和变量名之间的任何位置,如下int *p,q;等价于:int* p,q;p是整型指针变量,q是整型变量。第二种写法容易理解为p,q都是指针变量。故建议写成第一种形式。指针变量存储的内容是内存中某个字节的地址,指针变量占用的内存字节数随

5、系统的不通而不同。7.1.3 初始化指针定义了一个指针后,在使用此指针前,必须给它赋一个合法的值。在C+中,可以在定义指针的同时通过初始化来给指针赋值,也可以在使用之前给指针赋值。一般来说,C+在定义指针的同时初始化指针的形式如图7-7所示。图7-7 C+在定义指针的同时初始化指针的形式注意:当把一个变量的内存地址作为初始值赋给指针时,该变量必须在指针初始化之前已做说明,因为变量只有在说明之后才被分配一定的内存地址。此外,该变量的数据类型必须与指针的数据类型一致,因此不能将一个浮点型变量的地址赋值给整型的指针变量。同时,也可以向一个指针赋初值作为另一个指针变量,即把另一个已经初始化的指针赋给一

6、个指针。此时,这两个指针指向同一变量的内存地址,如图7-8所示。图7-8 两个指针指向同一变量的内存地址指针的初始化在具体程序中非常重要,一旦指针的初始化出现问题,就可能导致程序崩溃。【示例7-1】下面程序定义了整型指针变量p1和p2,并为其赋初值,其实现代码及结果如图7-9所示。图7-9 指针的初始化实例注意:在给指针变量初始化时,不能为其赋一个常量,否则程序将通不过编译。此外,上述程序中使用*p1和*p2取出其中存储的变量a的值,这是下面将要介绍的指针的访问问题。7.2 指针的访问如果定义一个指针,并使其值为某个变量的地址,则可以通过这个指针间接地访问在这个地址中存储的值。如示例7-1中,

7、通过*符号取出存储在该地址中的值。事实上,在C+中有两个有关指针访问的运算符,下面将依次进行说明。7.2.1 指针的值指针的值是一个地址。在C+中,为了取得一个变量的地址,引入了取地址运算符“&”来取得一个变量的地址,其语法如图7-10所示。图7-10 取地址运算符&注意:取地址运算符&只能应用于内存中存在的数据,如变量、数组元素等,不能用于表达式、常数或寄存器变量。【示例7-2】下面示例定义了两个指针变量p1和p2,其都指向整型变量a后将值分别输出,其实现代码及结果如图7-11所示。图7-11 指针的值实例上述代码在指针的定义中,指针变量是p1和p2而不是*p1和*p2,因此要对一个指针赋值

8、,等号左边不应该加*号。注意:C+中不允许把一个无效的地址,比如数字赋给指针。指针变量和一般的变量是类似的,存放的值是可以改变的。7.2.2 访问指针数据通过&运算符可以获取变量的地址,可将其赋值给指针,即完成了将指针指向该变量的操作。而C+可以通过“*”运算符将指针指向的变量值取出,进行各种运算。在C+中,*运算符为取值运算符,也称为指针运算符、指向运算符或间接运算符,*p代表p所指向的变量。【示例7-3】下面程序接收用户从键盘输入的两个整数,并通过*运算符将指针变量p1和p2的值取出并输出,其实现代码及结果如图7-12所示。图7-12 访问指针数据实例通过指针来访问变量是一种间接的方式,其

9、速度略慢于直接访问。但给程序的开发带来了很大的灵活性,其原因在于指针也是一个变量,可以在运行时修改其指向,从而达到“使用一个指针,访问多个变量”的目的。7.2.3 小结指针p由于引进了指针的概念,在程序中要注意区分下面三种表示方法所具有的不同意义。例如,有一个指针p,其不同格式代表的意义不同如图7-13所示。图7-13 指针p不同格式代表的意义【示例7-4】下面程序接收用户输入的两个整数后,分别输出p、*p和&p的值,实现代码及结果如图7-14所示。7.3 指针的算术运算指针变量也有加减运算,它可以与某个整型数相加减,也可以与指针相减。但指针与指针相加或相乘除都是没有意义的。指针的值是一个内存

10、地址,而一个内存地址可以用一个整型数表示。因此,指针的算术运算可以看做是整型数间的一个运算。7.3.1 指针与整数的加减运算指针与整数的加减运算是指将指针作为地址量加上或减去一个整数n,其意义及效果如图7-15所示。图7-15 指针与整数的加减运算由于指针可以指向不同数据类型,即数据长度不同的数据,所以这种运算的结果取决于指针指向的数据类型。例如一个int型(4字节大小)指针加减整型数的运算如图7-16所示。图7-16 int型指针加减整数的运算因此,对于某种数据类型的指针p来说,其实际操作如图7-17所示。图7-17 某种数据类型的指针p的实际操作7.3.2 指针加减1运算指针与1的加减运算

11、是一种特殊的指针与整数的加减运算。由于指针的加减1运算在具体程序中使用广泛,并有自己的表示方法,因此本小结将单独讲解。同样地,指针加减1单项运算也是地址计算,它具有指针与整数的加减运算特点,指针的加1、减1单项运算是指针中的地址值的变化。在C+中,指针p的加1、减1运算表示如图7-18所示。图7-18 指针p的加1、减1运算表示运算后指针地址值的变化量取决于它指向的数据类型。例如,一个int型指针p存放的地址为1000,当执行p+、p后其地址变化如图7-19所示。图7-19 执行p+、p后其地址变化指针加1、减1单项运算与前面所讲的自增自减运算符类似,也分为前置运算和后置运算,如图7-20所示

12、。图7-20 指针加1、减1单项运算分类当指针加1、减1运算和其他运算出现在一个表达式中时,要注意它们之间的结合规则和运算顺序。例如,表达式y=*p+的分析过程和运算顺序如图7-21所示。图7-21 表达式y=*p+的分析过程和运算顺序7.3.3 指针的相减运算指针的相减运算是指两个指针所指向的变量类型相同时可以进行减法运算。其运算结果是两个地址之间可存放的变量个数,而不是地址量。例如,两个int型指针px和py进行相减运算如图7-22所示。图7-22 指针的相减运算注意:指针变量也可以进行关系运算,用于比较两个指针是否相等。指针也可以赋值给相同类型的指针变量。7.4 特殊指针前面章节学习了数

13、组和函数,C+允许指针指向数组和函数。本节将见绍几种特殊的指针。7.4.1 数组指针在C+中,数组指针是一个指向数组的指针,其定义的一般形式如图7-23所示。图7-23 数组指针【示例7-7】下列程序定义了一个数组指针,并通过该指针指向某一整型数组,输出其中所有数组元素,其实现代码及结果如图7-24所示。图7-24 数组指针实例7.4.2 指向函数的指针函数指针在C+中,函数指针是一个指向函数的指针,即指针存储的是函数的首地址。其定义的一般形式如图7-25所示。图7-25 函数指针在定义了指向函数的指针变量后,在使用此函数指针之前,必须先给它赋值,使它指向一个函数的入口地址。由于函数名是函数在

14、内存中的首地址,因此可以将函数名赋给函数指针变量,赋值的一般语法格式如图7-26所示。图7-26 函数指针赋值【示例7-8】下面程序定义一个函数指针p,该指针指向实现两个整型值交换的swap()函数。在使用该函数指针p前为其赋值,并在main()函数中调用了该函数指针,实现代码及结果如图7-27所示。图7-27 函数指针实例7.4.3 指针数组指针数组就是其元素为指针的数组,如图7-28所示。图7-28 指针数组指针数组是指针的集合,其每一个元素都是指针变量,并且它们具有相同的存储类型和指向相同的数据类型。指针数组在使用前必须先声明,一般地说,C+中声明指针数组的一般形式如图7-29所示。图7

15、-29 指针数组的声明与普通指针类似,指针数组在使用前也必须先赋值,否则指针可能指向没有意义的值。指针数组赋初值与一般数组的赋值类似,可以在声明指针数组的同时进行初始化。【示例7-9】下面程序定义了一个指向字符串的包含5个元素的指针数组,初始化后将其倒序输出,其实现代码及结果如图7-30所示。图7-30 指针数组实例说明:要严格区分数组指针和指针数组噢!7.4.4 二级指针指针的指针虽然指针存储的是一个地址,但指针本身也是一个变量,在内存中占据一定的空间,并且具有一个地址,这个地址也可以利用指针来保存。因此,同样可以声明一个指针来指向它,这个指针称为指向指针的指针。在C+中,指向指针的指针也被

16、称为二级指针,在声明指向指针的指针时,其形式与声明指针类似,但需加上两个间接取值的运算符“*”,声明形式如图7-31所示。图7-31 二级指针的声明与定义【示例7-10】下面程序声明了一个指针p,一个指向指针的指针pp,将指针pp指向指针p,实现代码及输出结果如图7-32所示。图7-32 二级指针实例7.4.5 多级指针二级以上的指针多级指针是指含有多个间接取值运算符“*”的指针,其声明形式与二级指针类似,如图7-33所示。图7-33 多级指针的声明在C+中常用的是二级指针,多级指针只需了解就可以啦!在这不做详细讲解。7.5 指针的应用C+中,使用指针可使程序简单、可读性强,并且指针的使用非常

17、灵活。本节将重点讲解指针在数组、字符串、函数中的应用及动态内存分配。7.5.1 指向一维数组的指针任何数据类型中的数组元素,除了用数组名加下标的方法进行访问外,还可以用指针访问。用指针访问数组形式简单、使用灵活,程序的可读性强。1指针访问数组元素用指针指向数组就是让指针指向这段连续内存的首地址,即数组中第一个元素(下标为0)的地址。定义一个指向数组的指针变量,只要其与数组元素类型相同即可。由于数组是一段连续的内存,指针可以指向数组,而且可以通过加、减整数来移动指针。所以,可以通过指针来访问数组,即数组中的元素。使用指针访问数组,同用下标访问数组的效果是一样的。例如一个指向数组arr首地址的指针

18、p,访问第i+1个元素(下标为i),可以用*(p+i),也可以用arri,这两种方法是等价的。由于数组名代表的是数组的首地址,所以也可以用*(arr +i)来访问第i+1个元素,如图7-34所示。图7-34 指针访问数组元素【示例7-11】下面程序通过几种方式对数组元素进行访问,实现代码及结果如图7-35所示。图7-35 几种方式对数组元素进行访问无论是采用下标、地址还是指针都可以得到相同的访问结果。但是,在数组元素的访问中,使用指针进行访问更为灵活。2指向一维数组在实际程序中一维数组的使用最为频繁,因此使用指针指向一维数组是具体应用中使用最多的。【示例7-12】下面程序将一个数组的元素进行反

19、转,即第一个元素放到最后一个,第二个元素放到倒数第二个,依此类推,其实现代码及结果如图7-36所示。图7-36 指向一维数组的实例注意:在使用指针访问数组时不要越界,即保证指针指向数组第一个到最后一个元素。7.5.2 指向二维数组的指针多维数组尤其是二维数组在具体程序中的应用非常广泛,通过指针来访问二维数组元素也是常用的。对于一维数组array10而言,指针指向为数组的首地址,即&array0的值。而对于二维数组array1010而言,数组的首地址为&array00的值。因此,对于二维数组中的元素arrayij有多种访问方法如图7-37所示。图7-37 二维数组中的元素arrayij的访问方法

20、例如,一个数组a35中元素a23的三种等价访问方法如图7-38所示。图7-38 元素a23的三种等价访问方法在二维数组a35中,其是一个3*5的矩阵,包括三行,每一行都有起始地址。C+中以a0、a1、a2分别表示第0行、第1行、第2行的起始地址,即该行第0列元素的地址。注意:二维数组的a0、a 1、a2并不是一个元素,而是一行首地址,正如同一维数组名是数组起始地址一样。因此,a0的值等于&a00,a1的值等于&a10,a2的值等于&a20。【示例7-13】下面程序指向二维数组array首元素的指针p,通过几种指针访问元素的方式将数组中的元素依次输出,其实现代码及结果如图7-39所示。图7-39

21、 指向二维数组指针实例7.5.3 指向字符串的指针在C+中,字符串是用字符数组表示和存储的。数组的访问能够通过指针来实现,因此字符串也同样可以通过指针来访问。指向字符串的指针就是一个char类型的指针。与普通指针一样,字符串指针在使用前也必须先定义。例如,下面语句定义了一个字符串str,并定义了一个指向该字符串的指针p,并为该指针进行初始化。如图7-40所示。图7-40 指向字符串的指针【示例7-14】下面示例用字符串指针访问字符串,并使用字符串函数对字符串进行比较和计算长度操作,实现代码及结果如图7-41所示。图7-41 指向字符串指针实例7.5.4 指针作为函数参数在函数的参数列表中,可以

22、使用指针类型的参数。传递给指针参数的实参可以是一个指针变量,也可以是一个变量的地址。在C+中,使用指针作为参数可以提高传递参数的效率,而且在函数中可以修改实参指针所指变量的值。例如,下面声明函数function()时其形式参数就是一个int类型的指针,在调用函数function()时必须传入一个int型的指针变量,如图7-42所示。图7-42 指针作为函数参数注意:使用指针作为函数的形式参数,在调用该参数时传递的是地址。【示例7-15】下面程序将指针作为函数的参数进行传递,完成两个数之间的互相交换功能,使用的是地址传递的方式,其实现代码及结果如图7-43所示。图7-43 指针作为函数参数实例代

23、码“change(&x,&y);”中的change()函数成功地实现了x和y之间的数据交换,函数的形参是两个int型指针,将调用函数中的变量地址作为实参,赋值给形参,完成对调用函数中变量的处理。7.5.5 指针作为函数的返回值指针函数指针函数是指函数的返回值为指针类型。指针函数在调用后返回一个指针,通过指针中存储的地址值,主调函数就能访问该地址中存放的数据,并通过指针算术运算访问这个地址的前、后内存中的值。指针函数与一般函数的区别如图7-44所示。图7-44 指针函数与一般函数的区别在C+中,指针函数与一般函数的声明和定义形式类似,不同点在于其返回值必须为指针,其一般语法形式如图7-45所示。

24、图7-45 指针函数的声明在具体程序中,指针函数的优势在于其能够返回一组数据,因此指针函数多用于数组和字符串的处理。【示例7-16】下面程序定义了一个包含5个字符串的指针数组,将这些字符串进行比较后输出其中最大的一个,其实现代码及结果如图7-46所示。图7-46 指针函数实例注意:函数指针与指针函数不要混淆噢!7.5.6 动态内存分配指针存储的是内存地址,在使用指针的时候,需要保证指向地址的有效性。C+程序中的内存分配分为两种,如图7-47所示。图7-47 C+程序中的内存分配在C+中,通过关键字new和delete来实现程序的动态内存分配和回收,如图7-48所示。图7-48 动态内存分配和回

25、收其中,关键字new实现内存分配,如果需要对分配出的内存进行初始化,则在类型后面加上一个括号,并带有初始值。因此,C+中动态分配内存的一般形式如图7-49所示。图7-49 C+中动态分配内存的一般形式此外,通过关键字new分配的内存必须由开发者自己去释放。一块内存如果没有被释放,则可以一直存在到该应用程序结束。在C+中,使用delete来释放内存,其一般形式如图7-50所示。图7-50 delete释放内存的一般形式【示例7-17】下面程序为一个整数和一个整型数组动态分配内存空间,使用该空间存储用户输入的数组元素,最后将这些空间释放,实现代码及结果如图7-51所示。图7-51 动态内存分配实例

26、用new申请动态数组,格式如下:类型名 *指针变量名= new 类型名元素个数;其中,元素个数可以是变量。7.6 引用虽然指针的使用非常灵活和高效,但使用起来却不是非常方便。如果使用不当,很容易导致某些不易察觉的错误。为此,C+引入了引用。7.6.1 引用的应用在C+中,引用也是一种数据类型。引用不能独立存在,而只能依附于一个变量。所以定义一个引用必须指明是哪个变量的引用。定义一个引用包括目标变量的数据类型、引用修饰符“&”、引用的标识符及目标变量的标识符。其语法如图7-52所示。图7-52 引用的一般语法形式注意:此处的“&”不是取地址运算符,而是一个引用修饰符。引用一旦定义,则始终跟其目标变量绑定,而不能改变为其他变量的引用。假如b是变量a的引用,则在b的生命周期内,b始终都是a的引用,而不能再改变为其他变量的引用。此外,对于引用在其生命周期内完全可以替代其目标变量。也就是说,所有施加于引用上的操作,其效果等同于直接对引用的目标变量操作。而且一旦目标变量的值发生了改变,引用的值也会发生同样的改变。如图7-53所示的程序体现了引用的这个特征。图7-53 引用的特征鉴于引用的不可变更性,以及引用与目标变量的等价性,一个变量的引用也可以看做是该变量的别名。定义一个引用只不过是给变量另外命名。这样两个名字拥有一个实体,对一个名字的

温馨提示

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

评论

0/150

提交评论