再上一篇:第八章 指针和引用
上一篇:8.2 指针与数组
主页
下一篇:8.4 指针与函数
再下一篇:8.5 new与delete
文章列表

8.3 指针数组与指向指针的指针变量

《VC++程序设计基础》,讲述C++语言的语法和标准库,以及Visual C++ 函数库和MFC类库的使用,并附相关代码示例。

8.3.1 指针数组

前已述及,由若干个同类元素组成的一个集合,构成一个数组。由若干个同类型的指针所组成的数组称为指针数组,数组的每一个元素都是一个指针变量。定义指针数组的格式为:

《存储类型》 <类型> *<数组名>[<数组的大小>];

由于运算符[ ]的优先级比*高,说明“<数组名>与[<数组的大小>]”构成一个数组,再与*结合,指明是一个指针数组。类型指明指针数组中每一个元素所指向的数据类型。如:

int *p1[4];

float *p2[16];

将p1定义为一个指针数组,它由4个元素组成,每一个元素所指向的数据类型为整型。而p2被定义为另一个指针数组,它由十六个元素组成,每一个元素所指向的数据类型为实数。

例8.8 用指针数组输出数组各元素的值。

#include

void main(void)

{

float a[] = { 100,200 ,300 , 400, 500};

float *p[] = { &a[0],&a[1],&a[2],&a[3],&a[4]};

int i;

for ( i = 0; i < 5; i ++)

cout << *p[i] << "\t";

cout<<'\n';

}

执行程序后的输出为:

100 200 300 400 500

说明了一个指针数组p,它的每一个元素依次指向数组a中的每一个元素。就本例而言,没有必要使用指针数组,本例的目的是说明指针数组的简单用法。

例8.9 将若干个字符串按升序排序后输出。

str[0] Follow me

str[1] BASIC

str[2] Great wall

str[3] Department

str[4] Computer design

图8.4 排序前指针数组str的指向

分析:如图8.4所示,定义一个指针数组str,它的每一个元素指向一个字符串。首先找到再小的字符串,并使该指针值与str[0]中的值交换,使str[0]指向最小的字符串。接着找到次小的字符串,使 str[1]指向次小的字符串。依此类推,直到str[4] 指向最大的字符串。

排序后指针数组str中各个元素所指向的字符串如图8.5所示。采用这样的排序方法,要比交换字符串速度快,因为这里只交换指针而不交换字符串。str[0] Follow me

str[1] BASIC

str[2] Great wall

str[3] Department

str[4] Computer design

图8.5 排序后的str指向

#include

#include

void main(void)

{

char *str[] = {"Follow me ","BASIC ","Great wall","Department",

"Computer design"};

char *p1;

int i , j, k;

//按升序排序

for ( i = 0; i < 4 ; i++ ) {

k = i;

for ( j = i + 1 ; j < 5 ; j ++ )

if ( strcmp(str[k] , str[j] ) > 0 ) k = j ; //A

if ( k != i ) { //B

p1 = str[k] ; str[k] = str[i] ; str[i] = p1;

}

}

//输出排序后的字符串

for ( i =0 ; i < 5 ; i ++) cout <

}

执行程序后的输出为:

BASIC

Computer design

Department

Follow me

Great wall

A行中的函数strcmp( )是字符串比较库函数,str[k]和str[j]的值分别是第k个和第j个字符串的起始地址。如果str[k]指向的字符串大于str[j]所指向的字符串,则该函数返回的值大于0。这时,要将j的值赋给变量k。当执行完由j控制的内循环语句后,从第i个字符串到最后一个字符串之间的所有字符串中,第k个字符串为最小。B行中,若k不等于i,表示第i个字符串不是最小的字符串;要将str[k]和str[i]的值交换,也就是将指向第i个字符串的数组元素与指向第j个字符串的数组元素对换。当由i控制的外循环执行完后,排序结束。C行输出排序后的字符串。

8.3.2 指向一维数组的指针变量

在定义了一个一维数组后,再定义一个指针变量,使指针变量指向这个数组的起始地址后,则数组名可用指针变量来代替。设有如下说明:

int j,a[100],*p=&a[0];

则a[j]与p[j]的作用相同(j的值应在0~99之间)。对于二维数组,定义某一个指针变量后,是否也存在与一维数组类同的表示方法呢?回答是肯定的。我们用一个例子来说明之。

例 8.10 用不同的表示法输出二维数组中的元素。

#include

void main(void)

{

int a[3][4] = {{5,6,7,8},{9,10,11,12},{13,14,15,16}};

int i, j ;

int (*p)[4]; //A

//依次输出数组中的各个元素

cout<<”用行指针输出数组的各个元素:\n”

for ( i = 0 ; i < 3 ; i ++) {

p = &a[i]; //B

cout<<(*p)[0]<<"\t"<<(*p)[1]<<"\t"<<(*p)[2]<<"\t"<<(*p)[3]<<'\n';//C

}

p = a;

//输出数组中的各个元素

cout<<”用四种不同的方法输出数组的各个元素:\n”

for ( i = 0 ; i < 3 ; i ++)

for ( j= 0 ; j < 4 ; j++) {

// *(*(p+i ) +j), *(p[i] + j), *(*(a+i)+j),*(a[i]+j)都是指同一元素

cout << *(*(p+i)+j)<< "\t" << *(p[i]+j) <<"\t"; //D

cout << *(*(a+i)+j)<<"\t" << *(a[i]+j)<<'\n'; //E

}

}

执行程序后的输出为:

用行指针输出数组的各个元素:

5 6 7 8

9 10 11 12

13 14 15 16

用四种不同的方法输出数组的各个元素:

5 5 5 5

6 6 6 6

7 7 7 7

8 8 8 8

9 9 9 9

10 10 10 10

11 11 11 11

12 12 12 12

13 13 13 13

14 14 14 14

15 15 15 15

16 16 16 16

程序中A行:

int (*p)[4];

其中(*p)指明p是一个指针变量;再与[4]结合,表示该指针变量所指向的数据是一个一维数组,该数组由四个元素组成,或者说p指向包含四个元素的一维数组。注意,以上说明中的括号不可少。当没有括号时,表示p是一个指针数组。用指针变量p来访问它所指向的一维数组中的元素的方法如图8.6所示。从图中可以看出,p实际上是一个一维数组的行指针,它的值是该一维数组的起始地址。注意,p不能指向这一维数组中的第j个元素。

p (*p)[0] (*p)[1] (*p)[2] (*p)[3]

图 8.6 指针变量p的指向

程序中的B行是将数组a的第i行的起始地址赋给指针变量p。C行输出p所指向的一维数组中的各个元素值。

当把数组a的起始地址赋给p后,正如D行和E行中的用法那样,*(*(p+i )+j), *(p[i] + j), *(*(a+i)+j)和*(a[i]+j)的作用相同,都表示数组a的元素a[i][j]。从这种对应关系可以看出,在二维数组与指针中介绍的用数组名表示数组行列地址和元素的方法中,均可用这种指针来表示,只要将数组名换成这种指针变量名。

关于指向一维数组的指针变量,应注意以下几点:

1、说明语句“int (*p)[4];”中, p 是一个指针变量, 不是一个指针数组。当把二维数组的起始地址赋给p后,(*p)[0]是二维数组中第0行第0 列元素的值,而*(p+i)+j是一个地址,要把这二者区分开来。

2、定义这种指针变量时,它所指向的一维数组的元素个数应与二维数组的列数相同。否则,在使用时肯定会带来问题。

3、设有说明语句:

float (*pp)[N],x[M][N];

pp=x;

此时的pp=pp+1,是使指针变量pp指向二维数组的下一行;实际上,系统内部所做的运算是:

pp = pp+sizeof(float) * N

只能将数组的行地址赋给这种指针变量,不能将二维数组的元素地址赋给它。如:

pp = x[i];

是错误的,因x[i]表示第i行第0列元素的地址,而不是数组的行地址。如:

pp = &x[i]; //或pp = x+i;

是正确的。&x[i]和x+i都表示数组x的第i行的地址。

4、可把这种表示方法推广到三维或更多维的数组中,其表示方法要比二维数组更复杂。如定义指向二维数组的指针变量的方法为:

int *(ptr)[20][50];

定义了一个指针变量ptr,它指向一个具有20行50列的二维数组。这种指针变量的加1运算:

ptr = ptr+1

系统内部所做的实际运算是:

ptr = ptr+ sizeof(int) * 20 * 50

8.3.3 指向指针的指针变量

在C++语言中,当我们定义了一个指针变量p时,系统要为指针变量p分配内存单元。如果再定义一个指针变量pp,它指向指针变量p。这时称pp为指向指针的指针变量,简称为二级指针。定义二级指针的一般格式为:

《存储类型》 <类型> **P1;

定义一个二级指针变量时,在其前面有二个“*”。类同地定义三级指针变量,是在指针变量前加上三个“*”。在C++中,对定义指针的级数并没有限制。在程序设计中,通常使用一级(定义的指针变量前只有一个*)、二级、三级指针变量,更多级的指针变量很少使用。

例8.11 多级指针的简单使用。

#include

void main(void )

{

int i=10;

int *p1,**p2, ***p3;

p1 = &i; p2 =&p1, p3 =&p2;

cout << "i= " << *p1<<'\n';

cout << "Address of p1= " << p2<<'\n' ;

cout << "Address of p2= " << p3 <<'\n';

cout << "i= " << **p2<<'\n';

cout << "i= " << ***p3<<'\n';

}

执行程序时的输出为:

i= 10

Address of p1= 0x0064FDF4

Address of p2= 0x0064FDF0

i= 10

i= 10

程序中指针变量的指向关系如图8.7所示。

指针变量p1的值为变量i的起始地址,指针变量p2的值为p1的地址,指针变量p3的值为p2的地址。从图8.7及本例的输出可看出,在二级指针变量前加一个“*”得到的是一个地址;加上二个“*”才能得到数据值。这种规则可以推广到任意多维的指针变量。

P3: P2: P1: i:10

图8.7 多级指针示意图