指针——C++详解

来源:互联网 发布:机顶盒电影软件 编辑:程序博客网 时间:2024/06/15 18:17
众所周知,一个字节由8个二进制位组成,而内存又是由很多个字节组成的,就像一座拥有很多个房间的宾馆。如何访问存放在内存中的程序指令和数据呢?就像给宾馆每个房间编号一样,计算机给每个字节分配一个号码,通过相应号码来访问各个字节,这就是内存编址。这样内存就由连续编号的字节序列组成,程序的指令和数据存放在这些字节中。编号就是地址。地址也是数据,只不过它是一种指示内存空间位置的特殊数据。
如果把变量a的地址存放在变量b中,访问变量a之前先要访问变量b,得到变量b的值即变量a的地址,再去访问变量a。这种访问变量a的过程就称为间接访问。所谓间接访问,指的是先访问存放变量地址的存储单元,得到该变量的地址,再对变量内容进行访问。

1.指针变量
C++语言把变量的地址形象地称为指针,意思就是指针指向变量所对应的存储单元,通过它可以访问变量的值。
一个变量的地址可以称为该变量的指针,专门存放变量地址的变量称为指针变量
(1)变量的指针:常量,存放的是变量的地址。
(2)指针变量:变量,存放的是  变量的指针(即变量的地址)。

指针变量的定义形式是:类型 *变量名;
例如: int a, *b;//定义了一个普通整型变量a和一个整型指针变量b(指的是指针变量b存放了一个普通整型变量的地址)。

和指针有关的运算主要有赋值、取地址、间接访问以及加减运算等。取地址的运算符是&,间接访问的运算符是*。两个运算符均为单目运算符,而且作用正好相反,互为逆操作,即 &*p等价于p。

(1) & 取地址运算符,p=&a,p中存放的是a的地址;

(2)* 间接访问, *p 访问的是p中存放的地址指向的值。

例如: int a=3,*p;

    p=&a;

    此时,p=0x0012ff7c,*p=3;


指针变量只能指向同类型的普通变量,void类型指针可以称为空指针,也称为万能指针,任何类型的指针都可以赋给void类型的指针变量,再经过强制类型转换之后,又可以间接访问任意类型的变量。


2. 指针与数组

指针与数组有着密切的联系。数组名表示数组的起始地址,而数组元素又是在内存中顺序存放的,因此利用指针的移动可以很方便地实现对数组各个元素的访问。如果把数组a的起始地址赋给一个指针变量p,变量p就指向了数组的第一个元素a[0]。由于a[0]的下一个元素是a[1],因此p+1指向元素a[1],同理p+2指向元素a[2]。以此类推,p+i指向数组元素a[i],这就是一维数组与指针变量的关系。

例如:int a[3],*p;

   p=a;//p=a也可以写成p=&a[0];


二维数组的指针较一维数组的指针要复杂的多。在C++中认为二维数组是一个特殊的一维数组,其长度为行数,每一行是该特殊一维数组的一个元素;该一维数组的每一个元素即一行,又是一个一维数组,其长度均为列数,由组成该行的所有列的元素组成。

例如:int a[2][2];

*(a+0)可以访问a[0],*(a+1)可以访问a[1]。其次a[0]和a[1]又分别是两个一维数组(即两行)的数组名,因此*(a[0]+0)可以访问a[0][0],*(a[0]+1)可以访问a[0][1]。*(a[1]+0)可以访问a[1][0],以此类推。


为配合二维数组的指针,C++语言还提供了指向一维数组的指针,也称为行指针

行指针的语法形式是: 类型 (*变量名) [常量表达式];

说明:“()”不能省略,否则就不是指向一维数组的指针,而是指针数组。只想一维数组的指针是二级指针,它不直接指向某一个数组的元素。二维数组名不能赋给一级指针变量,但是可以赋给指向一维数组的指针,不过该一维数组的长度一定要与二维数组列的长度相等。


普通数组的元素相当于一个普通变量,如果某种数组的元素是指针变量,那么就把这种数组称为指针数组。指针数组的元素是一些具有相同类型的指针变量,每一个元素可以指向一个普通变量。

指针数组的语法形式是: 类型 *数组名[常量表达式];

深入分析一下指针数组的语法,会发现指针数组的元素是指针变量,指针数组的名字又是数组的起始地址,即数组首元素的地址,那么指针数组名就是一个指向指针变量的指针。C++语言允许定义指向指针的指针变量,其语法形式是:类型 **变量名;

与一级指针相比,指向指针的指针定义时多了一个*,它属于二级指针。指向指针的指针也可以用来访问存放在内存的数据,只不过要连用两次间接访问运算符(*),这种访问方式称为二次间接访问。指向指针的指针在使用时,需要先指向一个一级指针。

例如: int **p, *q;

    p=&q;


3.对象指针

C++语言允许程序员定义对象指针变量,存放某一个已创建的对象的地址,即指向该对象。

对象指针变量的定义形式是: 类名*变量名;//与普通指针的区别在于指针的类型是类

借助于->运算符,可以通过对象指针间接访问所指对象的外部接口。其一般形式为:对象指针->公有成员函数名(实参表);

例如:point a, *p; //定义一个普通对象a和一个对象指针变量p

   p=&a;//p指向a

   p->display();//激活对象a的display方法

在对象指针p已指向对象a的前提下,p->display()的效果与a.display()是完全等价的。前者是间接访问,后者是直接访问。


C++语言提供this指针,他是一个特殊的对象指针,指向对象自身。this指针被隐含地用来访问对象的数据成员和成员函数。系统只为对象的数据成员分配内存空间,而类的成员函数只保留一个副本,被类的所有对象所共享。成员函数如何知道是哪一个对象调用它呢?通过this指针绑定目标对象。实际上this指针是成员函数的一个隐形形参,应该出现在形参表的第一个位置。

例如:point类的成员函数move,其原型是void move(int xx, int yy);,表面上看只有两个整型的形参,其实还有一个对象指针作为第一个形参,它就是this指针。成员函数move真正的原型是 void move(point *this, int xx, int yy);。对象调用成员函数时,例如 a.move(1,1,);,C++编译器自动把该语句转换为move(&a,1,1);,通过形实结合,this指针就指向了对象a,使得成员函数move最终找到调用它的对象a。


4.成员指针

对象的数据成员在内存顺序存放,这些成员具有数据类型,分别占据一定的空间,也拥有自己的地址。因此不仅可以定义对象指针,还可以定义指向成员的指针。指向成员的指针既能够指向对象的数据成员,也可以指向对象的成员函数。其语法形式是:

类型 类名::*成员指针名;  //定义指向数据成员的指针

类型 (类名::*成员指针名) (形参表); //定义指向成员函数的指针

例如:

point a;  //定义一个普通对象a

int point::*p1;  //定义指向point类成员函数的指针p1

void (point::*p2)(void); //定义指向point类成员函数的指针p2

p2=point::display; //p2指向point类的成员函数display

在定义成员指针时,用类名::的形式标明该指针的性质;在建立成员指针的指向关系时,其所指成员不仅要用类名::的形式标明身份,而且成员指针与所指成员的类型还要保持一致。特别是指向成员函数的成员指针,它的形参表也要与所指的成员函数一致。由于类成员的访问控制属性的因素,不允许在类的外部将私有成员的地址直接赋给成员指针。

如何通过成员指针访问所指成员呢?C++语言提供了两个用于成员指针访问的运算符:.* 和 ->*  均为双目运算符。 .* 运算符的左操作数是对象,右操作数是成员指针; ->* 运算符的左操作数是对象指针,右操作数是成员指针。以指向成员函数的成员指针为例,使用形式是:

 (对象 .* 成员指针) (实参表);

(对象指针->* 成员指针) (实参表);

0 0
原创粉丝点击