1、第六章 指针、引用和动态空间管理,6.1 指针的概念和指针变量的定义,指针的概念 内存空间是顺序排列的以字节为单位的存储单元 对内存空间的存储单元编号即地址 变量名实际上是某个存储单元的名字,对变量的存取就是对该存储单元进行存取。 存储单元也可以用它的地址进行存取,由于地址指明了数据存储的位置,因此形象地称之为指针,该地址存放的数据称之为“指针所指向的数据”,指针,指针与地址有概念上的区别,指针是有特定数据类型的,而地址就是存储单元的编号,无数据类型。 指针的类型就是指针所指向的数据的类型,例如double型指针就是只能用于指向double型数据的指针 无类型指针(void指针),可用来指向任
2、何类型的数据的指针,指针变量的定义和初始化,指针变量是专门用于存放地址的变量 定义格式: 类型修饰符*变量名=指针表达式 例: int * t ;/定义了一个整型指针变量t double * pn , * ph; /定义了两个整型指针变量pn和ph,double d , *pd1=/定义了一个长整型指针变量pd5, 初值为NULL(空),pd5是一个空指针, 即不指向任何数据,常值指针,定义时可将指针变量定义为常值指值 两种含义的常值指针 1、指针指向的值是常值 2、指针本身为常值,指针指向的值是常值的常值指针,定义时const放在*号之前 例如: const char *s=“Hello!”
3、 /定义指针s指向字符串“Hello!”,它指向的“Hello!”值不能改变,指针本身可以改变,即指针s也可以指向别的存储空间,因此,以下语句中, s=“Hi!”; /正确,改变指针本身,让s指向另一字符串 *s=Y; /错误,试图改变s指向的空间的数据,指针本身为常值,定义时const放在变量名之间,*号之后 例如: char * const s=“Hello!” /定义指针s指向字符串“Hello!”,s只能指向该字符串所在的空间,不能指向其它地址,而s指向的数据可以改变,因此,以下语句中, s=“Hi!”; /错误,试图改变指针本身,让s指向另一字符串 *s=Y; /正确,改变s指向的空
4、间的数据,6.2 指针的基本操作,取变量地址:操作符& 例:&d:取变量d的地址值,指针(变量)赋值:(操作符=) 只能把地址值赋值给指针变量 例:int k, *p; p=,间接访问:操作符 * 通过*可以进行间接访问指针所指向的存储空间 例: int * pd,d; pd=/输出99 99 *与&是两个互逆的操作,*&k=3与k=3完全相同,判断一指针是否空指针,空指针:NULL(或地址值为0的指针) 判断指针p是否空指针的表达式:if(p= =NULL)if(p= =0) if(!p) /C+风格的表示法 判断指针p是非空指针的表达式:p!=NULL或p!=0或p 也可比较指针大小,与一
5、般变量的比较相同,计算两地址间数据单元的个数,用指针相减可计算两地址间数据单元的个数 例:int n,m12,*p1= /n得5注: 可容纳5个整型数据(不把被减数那个指针所指向的数据计算在内) 一般是高地址减低地址指针才有意义,指针移动,向后(高地址)移动n个单位 指针表达式 + n 指针变量+ = n 向前(低地址)移动n个单位 指针表达式 - n 指针变量- =n 移动n个单位,则移动了n*sizeof(TYPE)字节 例: int m12,*p=,移动一个单位,对指针p移动一个单位 p+或+p:向后(高地址)移动一个单位 p或p:向前(低地址)移动一个单位 注意前增(减)与后增(减)对
6、变量的作用。 例1: int k, *pk= /输出指针变量的值,比上面表达式的值 增1*sizeof(int),指针类型的强制转换,指针类型强制转换格式: (类型修饰符 *)指针表达式 例: short i=258; /在内部为二进制,并占两字节,低字节为00000001,高字节为00000010 char *p=(char *) /输出21,指针操作符的综合运用,假定指针p定义如下: int d=3,6,9,*p=d; 请注意区分以下指针表达式的含义: *p+:取p所指向单元的数据作为表达式的值,然后 使p指向下一个单元; (*p)+:取p所指向单元的数据作为表达式的值,然后 使该单元的数
7、据值增1; *+p:使p指向下一单元,然后取该单元的数据作为 表达式的值; +*p:将p所指向单元的数据值增1并作为表达式的值。,6.3 指针与数组,一维数组元素的指针访问方式,一维数组的数组名实际上就是指向该数组第1个元素的指针 例:int A10; /则数组名A是一个指向A0的指针常量int *pa=A;/因此可以赋值给一个指针变量且指针间接访问:*A等价于A0,数组名传统上采用下标访问,但也可以采用指针访问方式:Ai等价于*(A+i)A0等价于*(A+0)等价于*A 指向一维数组第1个单元的指针可以像一维数组名那样使用,例如代替数组名进行下标访问。例:int A10,*pa=A; /Ai
8、等价于*(pa+i)和pai,多维数组元素的指针访问方式,了解二维数组元素的指针访问方式 例:int B68; 把B看成是具有六个元素的一维数组,其中每个元素是一个有8个元素的int型一维数组 因此,数组名B的类型为int(*)8 数组名是指向二维数组首行的指针 下标访问方式与指针访问方式的等价关系: Bij*(Bi+j) *(*(B+i)+j),指向二维数组首行的指针int B1020,(*pb)20=B; 指向整个二维数组的指针int (*pb)1020= 指向二维数组首行的任何指针可以像二维数组名那样使用,可下标访问也可指针访问,指向数组的指针应理解为与该数组名等价的指针,这样的指针可用
9、于访问该数组定义指向数组的指针的格式: 指向一维数组:类型修饰符*变量名=一维数组名 指向二维数组:类型修饰符*变量名列数=二维数组名在函数形参中定义数组参数(即定义指向数组的指针)格式: 指向一维数组:类型修饰符*变量名=一维数组名 指向二维数组:类型修饰符*变量名列数=二维数组名,字符指针与字符串,字符型指针:char s1=“string1”,*p1=s1; 数组名代表存储于其中的字符串,是指向字符串第一个字符的指针 字符串常量实际上是指针,是指向存储该字符串的无名字符数组首单元的指针,指针数组,数组的每个元素是指针的数组称为指针数组 定义格式:类型修饰符*数组名元素个数 = 初值表 ;
10、类型修饰符*数组名行数列数=初值表, 初值表; 例:int *ip10; /ip是一维指针数组,区别于int (*ip)10double *dp58; /dp是二维指针数组char * MONTH=NULL,”January”,”Feburay”,”March”,”December”,数组参数实际上是指针,在参数说明时,指定一维数组的元素个数及多维数组的行数并无意义,无需指定。 在函数定义中,数组参数实际上是指针,如: int sum(int array,int size); void sumAll2(int data5, int result, int rows); int array也可以
11、说明为int *array; int data5也可说明为指向二维数组的指针int (*data)5,6.4 指针与函数,指针参数 函数调用时,指针参数的传值是把实参指针所指向的数据间接地传递给被调用的函数,如数组参数 这种传指针方式,形参指针与实参指针指向同一数据,因此通过形参指针就可以改动实参数据。,例: int addTo(int data, int *agg) return *agg+=data; void main( )int total=0;addTo(5,结果为:513 传指针方式传递参数,函数调用时直接改变实参数据,利用传指针方式除了可以达到函数调用时直接改变实参数据外,也可以
12、减少参数传递过程中的数据复制量,以达到节省空间,提高效率的目的。P169例6.6请看书本自学,指针函数,指针函数:返回指针值的函数 定义指针函数格式: 类型修饰符 * 函数名(形式参数表)函数体,例: char * trim(char *s) char *p=s+strlen(s)-1; /p指向s的最后一个字符 while(p-s=0 函数的功能是截去参数字符串的尾部空格,并返回截去尾部空格后的字符串。,函数指针,指向函数的指针称为函数指针。 若一函数的原形为:类型修饰符 函数名(形式参数表)则指向该函数的指针变量应定义为类型修饰符 (*变量名)(形式参数表)=函数名 函数指针的一个重要用途
13、是将函数本身作为参数传递给另一个函数。,引用,定义一个引用就是为一个变量、函数等对象规定一个别名。 定义格式: 类型修饰符&别名=别名所代表的对象 别名就是一个变量 别名所代表的对象就是一个变量名或函数名,例: int i=0; int 可施加于引用的操作取决于引用所代表的对象的数据类型。,引用所代表的对象不同,定义引用的格式也不同 int a10,*p=a; int /rp2代表p所指向的那个对象,即数 组元素a0,设计函数swap,其功能是交换两个变量的值。要求变量的地址通过指针参数传递。,#include void swap(int *a,int *b) int c=*a; *a=*b;
14、 *b=c; void main( )int x=3,y=5;swap( ,设计函数swap,其功能是交换两个变量的值。要求变量的地址通过引用参数传递。,#include void swap(int ,动态空间管理,C+中提供了在程序运行时动态地取得和释放空间的机制,这样的空间叫动态空间,也叫自由空间。申请动态空间new 释放动态空间delete,非数组动态空间,申请动态空间的格式:new 类型说明(表达式) 如果申请空间成功,返回一个指向该内存空间的指针,指针类型由类型说明确定,括号内的表达式是对于申请到的内存的初始化。 释放空间的格式:delete 指针表达式,指针表达式,例:int *p
15、1,*p2;p1=new int(5); /申请整型空间,并初始化为5p2=new (int *); /申请一整型指针空间(括号可省)*p2=new int(7); /*p2指向一整型空间,初始化为7coutendl*p1 *p2;delete p1,*p2,p2; /释放指针p1、*p2及p2所指向的空间,数组动态空间,申请数组动态空间 new 类型说明元素个数 new 类型说明行数列数 对于申请的数组空间,无法初始化 释放数组动态空间 delete 指针表达式, 指针表达式,例: int *ap=new int10; /指针ap指向申请到的具有10个元素的整型数组空间。 double (*Matrix)20=new double2020;/指针Matrix指向申请到的双精度实型二维数组。 delete ap,Matrix;/释放指针ap和指针Matrix指向的数组空间,