指针与数组
Posted 松子茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指针与数组相关的知识,希望对你有一定的参考价值。
用指针变量来访问数组中任一元素,通常将数组的首地址称为数组的指针,而将指向数组元素的指针变量称为指向数组的指针变量。使用指向数组的指针变量来处理数组中的元素,不仅可使程序紧凑,而且还可提高程序的运算速率。
一维数组与指针
数组指针
数组的首地址称为数组指针。若定义整型数组a[5],系统为数组分配的地址从1000到1019,如图7.5所示,则数组a的首地址1000为数组a的数组指针。C++规定,数组的首地址可用数组名a表示,因此,数组a的数组指针=a=&a[0]。
数组指针变量
存放数组元素地址的变量称为数组指针变量。如:
int a[5];
int *p=&a[0];
则p为数组指针变量。在C++中数组名a可用于表示数组的首地址,所以数组名a可作为数组指针使用。因此:p=a与p=&a[0] 的作用是相同的。但数组名a不能用来进行赋值运算、”++”、”- -“等运算。
当指针变量指向数组首地址后,就可使用该指针变量对数组中任何一个元素变量进行存取操作。现举例说明如下:
【例1】用指针变量访问数组元素。
#include <iostream.h>
void main( void)
int a[5]=0,1,2,3,4,i,j,*p,n=5;
p=a;
for (i=0;i<n;i++)
cout <<*p<<'\\t';
p++;
cout<<endl;
p=a;
for (i=0;i<n;i++) cout <<*(p+i)<< '\\t';
cout<<endl;
for (i=0;i<n;i++) cout <<*(a+i)<< '\\t';
cout<<endl;
for (i=0;i<n;i++) cout <<p[i]<< '\\t';
cout<<endl;
执行程序后,输出:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
由上例可以看出,访问数组元素值有三种方法:
(1)通过移动指针变量,依次访问数组元素。如:
p=a;
for (i=0;i<n;i++)
cout <<*p<<'\\t'; p++;
首先将指针变量p指向数组a的首地址。然后用*p
输出数组第i个元素的值,每次输出后用p++移动指针到下一个元素,依次循环直到结束。
注意:cout <<*p<<'\\t'; p++;
可合并为一条语句:cout<<*p++<<'\\t';
(2)指针变量不变,用p+i或 a+i 访问数组第i个元素。如:
for (i=0;i<n;i++) cout <<*(p+i)<< '\\t';
for (i=0;i<n;i++) cout <<*(a+i)<< '\\t';
在C++中允许用p+i 或a+i 表示第i 个元素的地址。因此,*(p+i)
与*(a+i)
均表示第i个元素的内容。
(3)以指针变量名作为数组名访问数组元素。如:
for (i=0;i<n;i++) cout <<p[i]<< '\\t';
若用指针变量名p作为数组名,则p[i]表示数组的第i个元素a[i]。
数组元素的引用
综上所述,对一维数组a[ ]而言,当p=a后,有如下等同关系成立:
① p+i=a+i=&a[i],即p+i、a+i 均表示第i个元素的地址&a[i]。
② *(p+i) =*(a+i)=p[i]= a[i]。即*(p+i), *(a+i), p[i]均表示第i个元素值a[i]。
其中p[i] 的运行效率最高。
由上所述可知:一维数组的第i个元素可用四种方式引用,即: a[i]、*(p+i) 、*(a+i)、p[i]。
二维数组与指针
二维数组元素在内存中的存放方式
在C++中,二维数组元素值在内存中是按行的顺序存放的。若定义二维整型数组a[3][3],假设编译系统为数组a分配的内存空间从1000开始到1035为止,则数组中各元素a[0][0]~a[2][2]在内存中按行存放次序如图7.6所示。因此,与一维数组类似,可用指针变量来访问二维数组元素。
【例2】用指针变量输出二维数组各元素的值。
# include <iostream.h>
void main(void)
int a[3][3]=1,2,3,4,5,6,7,8,9;
int *p=&a[0][0]; //将二维数组首地址赋给指针变量p
for (int i=0;i<9;i++)
cout<<*p<<'\\t'; //输出二维数组中第i个元素值
p++; //指针变量p加1,指向下一个元素
程序执行后输出结果为:
1 2 3 4 5 6 7 8 9
但要用上述指针变量p访问二维数组中任意指定元素a[i][j]就觉得很不方便,为此C++设计者提供另外几种访问二维数组元素的方法,为了了解访问二维数组元素的方法,必须了解三个地址概念,即:二维数组行首地址、行地址、元素地址,现介绍如下。
二维数组行首地址
二维数组各元素按行排列可写成如图7.7所示矩阵形式,若将第i行中的元素a[i][0]、a[i][1]、a[i][2]组成一维数组a[i] (i=0,1,2),则二维数组a[3][3]可看成是由三个一维数组元素a[0]、a[1]、a[2]组成。即:a[3][3]=(a[0],a[1],a[2]),其中:a[0]、a[1]、a[2]是分别表示二维数组a[3][3]的第0、1、2行元素。
即:a[0]=(a[0][0],a[0][1],a[0][2])
a[1]=(a[1][0],a[1][1],a[1][2])
a[2]=(a[2][0],a[2][1],a[2][2])
因为数组名可用来表示数组的首地址,所以一维数组名a[i]可表示一维数组 (a[i][0],a[i][1],a[i][2])的首地址&a[i][0],即可表示第i行元素的首地址。因此,二维数组a中第i行首地址(即第i行第0列元素地址)可用a[i]表示。
由例 1可知,一维数组的第i个元素地址可表示为:数组名+i。因此一维数组a[i]中第j个元素a[i][j]地址可表示为:a[i]+j ,即:二维数组a中第i行第j列元素a[i][j]的地址可用a[i]+j来表示,而元素a[i]][j]的值为:*(a[i]+j)。
【例3】定义一个3行3列数组,输出每行的首地址及所有元素值。
# include <iostream.h>
void main(void)
int a[3][3]=1,2,3,4,5,6,7,8,9;
for (int i=0;i<3;i++)
cout<<"a[" <<i<<"]="<<a[i]<< "="<<&a[i][0]<<endl;
for (int j=0;j<3;j++)
cout<<"a[" <<i<<"]["<<j<<"]="<<*(a[i]+j)<< "="<<a[i][j]<<endl;
程序执行后输出:
a[0]=0x0065FDD4=0x0065FDD4
a[0][0]=1=1
a[0][1]=2=2
a[0][2]=3=3
a[1]=0x0065FDE0=0x0065FDE0
a[1][0]=4=4
a[1][1]=5=5
a[1][2]=6=6
a[2]=0x0065FDEC=0x0065FDEC
a[2][0]=7=7
a[2][1]=8=8
a[2][2]=9=9
由此例输出结果可看出a[i]=&a[i][0] (i=0,1,2),这表明a[i]确实可以表示第i行首地址(即第i行第0列地址)&a[i][0]。
应注意,由于数组在内存的地址是由操作系统动态分配,因此,实际输出的各行首地址并不会如图7.5所假设的从1000到1035。通常地址用十六进制数表示,如在本例中:第0行实际首地址是:a[0]=0x0065FDD4。第1行实际首地址是:a[1]=0x0065FDE0。第2行实际首地址是:a[2]=0x0065FDEC。
二维数组行地址
为了区别数组指针与指向一维数组的指针,C++引入了行地址的概念,并规定二维数组a中第i行地址用a+i或&a[i]表示,行地址的值与行首地址的值是相同的,即:
a+i=&a[i]=a[i]=&a[i][0]
但两者类型不同,所以行地址a+i与&a[i]只能用于指向一维数组的指针变量,而不能用于普通指针变量,例如:
int a[3][3];
int *p=a+0;
则编译第二条指令时将会出错,编译系统提示用户p与a+0的类型不同。如果要将行地址赋数组指针变量,必须用强制类型转换,如:
int *p=(int *) (a+0);
二维数组名a可用于表示二维数组的首地址,但C++规定该首地址并不是二维数组中第0行第0列的地址(即a≠a[0][0]),而是第0 行的行地址,即a=a+0=&a[0]。
二维数组的元素地址与元素值
知道了二维数组的行地址与行首地址后,可以讨论二维数组的元素地址。
因为 a[i]=&a[i]= (a+i),所以 *(a+i) 可以表示第 i行的首地址。因此二维数组第i行首地址有三种表示方法:a[i] 、*(a+i)、&a[i][0]
。
由此可推知:第i行第j列元素a[i][j]的地址有四种表示方法:
a[i]+j 、*(a+i)+j、&a[i][0]+j、&a[i][j]
而第i行第j列元素a[i][j]值也有四种表示方法:
*(a[i]+j) 、 *(*(a+i)+j)、*(&a[i][0]+j)、a[i][j]
现将二维数组有关行地址、行首地址、元素地址、元素值的各种表示方式总结归纳如表1 所示:
表1 二维数组a的行地址、行首地址、元素地址、元素值的各种表示方式
目录 | 行地址 | 元素地址 | 元素值表示方式 |
---|---|---|---|
第i行行地址 | a+i | &a[i] | |
第i行首地址(第i行第0列地址)a[i] | *(a+i) | &a[i][0] | |
元素a[i][j]的地址 a[i]+j | *(a+i)+j | &a[i][0]+j | &a[i][j] |
第i行第j列元素值 *(a[i]+j) | *(*(a+i)+j) | *(&a[i][0]+j) | a[i][j] |
为了加深读者对二维数组a的行地址、行首地址、元素地址、元素值的各种表示方式的理解,现举例如下:
【例4】定义二维数组a[3][3],用二种方式输出行地址,用三种方式输出行首地址,用四种方式输出所有元素地址及元素值。
# include <iostream.h>
void main(void)
int a[3][3]=1,2,3,4,5,6,7,8,9;
for (int i=0;i<3;i++)
cout<<"&a["<<i<<"]="<<&a[i]<<"="<<a+i<<endl; //输出第i行行地址
cout<<"a["<<i<<"]="<<a[i]<<"="<<*(a+i)<<"="<<&a[i][0]<<endl; //行首地址
for (int j=0;j<3;j++)
cout<<"&a["<<i<<"]["<<j<<"]="<<a[i]+j<<"="<<*(a+i)+j<<"="<<
&a[i][0]+j<<"="<<&a[i][j]<<endl; //输出元素a[i][j]的地址
cout<<"a["<<i<<"]["<<j<<"]="<<*(a[i]+j)<<"="<<*(*(a+i)+j)<<
"="<<*(&a[i][0]+j)<<"="<<a[i][j]<<endl; //输出元素a[i][j]的值
程序执行后输出结果为:
&a[0]= 0x0065FDD4=0x0065FDD4
a[0]= 0x0065FDD4=0x0065FDD4=0x0065FDD4
&a[0][0]= 0x0065FDD4=0x0065FDD4=0x0065FDD4=0x0065FDD4
a[0][0]=1=1=1=1
&a[0][1]= 0x0065FDD8=0x0065FDD8=0x0065FDD8=0x0065FDD8
a[0][1]=2=2=2=2
&a[0][2]= 0x0065FDDC=0x0065FDDC=0x0065FDDC=0x0065FDDC
a[0][2]=3=3=3=3
&a[1]= 0x0065FDE0=0x0065FDE0
a[1]= 0x0065FDE0=0x0065FDE0=0x0065FDE0
&a[1][0]= 0x0065FDE0=0x0065FDE0=0x0065FDE0=0x0065FDE0
a[1][0]=4=4=4=4
&a[1][1]= 0x0065FDE4=0x0065FDE4=0x0065FDE4=0x0065FDE4
a[1][1]=5=5=5=5
&a[1][2]= 0x0065FDE8=0x0065FDE8=0x0065FDE8=0x0065FDE8
a[1][2]=6=6=6=6
&a[2]= 0x0065FDEC=0x0065FDEC
a[2]= 0x0065FDEC=0x0065FDEC=0x0065FDEC
&a[2][0]= 0x0065FDEC=0x0065FDEC=0x0065FDEC=0x0065FDEC
a[2][0]=7=7=7=7
&a[2][1]= 0x0065FDF0=0x0065FDF0=0x0065FDF0=0x0065FDF0
a[2][1]=8=8=8=8
&a[2][2]= 0x0065FDF4=0x0065FDF4=0x0065FDF4=0x0065FDF4
a[2][2]=9=9=9=9
此例可说明表1中的二维数组a的行地址、行首地址、元素地址、元素值的各种表示方式是正确的。
以上是关于指针与数组的主要内容,如果未能解决你的问题,请参考以下文章
假设一棵树的存储结构采用双亲表示法,双亲指针数组为int parent[MaxSize],其中MaxSize表示双亲指针数组的最大结点个数。树中各个结点按先根遍历次序存放,根结点存于parent[0]