以下是我对二级指针与二维数组的理解。如有误,请告知作者!感激不尽!
在理解二级指针与二维数组的关系时,我们先来回顾一下一维数组与指针的关系:一维数组是由已知数目的相同类型的元素组合而成,每个元素依次连续排列在内存某一个空间中,因此每相邻两个元素的地址相差为同一个常数。数组名就是该数组的地址,数组取第一个元素的地址作为地址。此时我们可以用指针访问一维数组。实现过程如下:
#include<stdio.h>
int main(void)
{
int a[3]={0};
int* p=NULL;
int i=0;
p=a;
printf("&a[i]:");
for(i=0;i<3;++i)
printf("%d ",&a[i]);
printf("\np+i:");
for(i=0;i<3;++i)
printf("%d ",p+i);
printf("\na[i]:");
for(i=0;i<3;++i)
printf("%d ",a[i]);
printf("\np[i]:");
for(i=0;i<3;++i)
printf("%d ",p[i]);
printf("\n*(p+i):");
for(i=0;i<3;++i)
printf("%d ",*(p+i));
return 0;
}
&a[i]:921511572 921511576 921511580
p+i:921511572 921511576 921511580
a[i]:0 0 0
p[i]:0 0 0
*(p+i):0 0 0
从上面我们可以得出一些结论:&a[i]与p+i等价,p[i]与a[i]与(*(p+i))等价。且在数值上a=&a[0], a[i]=*(p+i)
现在我们来回顾二维数组:
#include <stdio.h>
int main(void)
{
int i,j;
char board[3][3] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'}
};
for(i = 0 ; i < 3; ++i)
for(j=0;j<3;++j)
printf(" board[%d][%d]: %c\n", i,j,*(*(board+i)+j));
return 0;
}
运行结果:
board[0][0]: 1 board[0][1]: 2 board[0][2]: 3
board[1][0]: 4 board[1][1]: 5 board[1][2]: 6
board[2][0]: 7 board[2][1]: 8 board[2][2]: 9
此时在数值上*board=board=board[0] = &board[0][0]=&board[0]=第一个元素的地址。board[0]相当于是每一个一维数组的数组名!
那么用malloc创建的“二维数组”是否具有这样的特性吗?
malloc创建“二维数组”的实现过程如下:
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
int i,j;
int row=3;
int column=3;
int **a;
a=(int**)malloc(row*sizeof(int*));
for(i=0;i<row;++i)
a[i]=(int*)malloc(column*sizeof(int));
for(i=0;i<row;++i)
for(j=0;j<column;++j)
scanf("%d",&a[i][j]);
for(i=0;i<row;++i)
for(j=0;j<column;++j)
printf("%d ",a[i][j]);
return 0;
}
也许此时会有疑问:二维数组为什么不能当作二级指针?上面这幅图貌似可以说明二维数组是二级指针?
其实上面这幅图正好能说明二维数组不是二级指针。我们知道数组中的每个元素依次连续排列在内存某一个空间中,因此相邻两个元素的地址值相差为同一个常数,因此我们可以看一下上面这幅图中相邻两个元素地址相差值:
36667440 36667444 36667448
36667472 36667476 36667480
36667504 36667508 36667512
而二维数组每个元素地址相差值:
886410672 886410676 886410680
886410684 886410688 886410692
886410696 886410700 886410704
我们再看一下是否满足a=&a[0]=a[0]=&a[0][0]:
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
int i,j;
int row=3;
int column=3;
int **a;
a=(int**)malloc(row*sizeof(int*));
for(i=0;i<row;++i)
a[i]=(int*)malloc(column*sizeof(int));
printf("a=%d,&a[0]=%d,a[0]=%d,&a[0][0]=%d",a,&a[0],a[0],&a[0][0]);
return 0;
}
运行结果如下:
a=8261160, &a[0]=8261160,a[0]=8261216,&a[0][0]=8261216
从上面可再次看出二维数组不是二级指针!
通过malloc创建的“二维数组”其实是指针数组,指针能代表内存中一块连续空间,因此要使用两次malloc。第一次用malloc分配一块空间,里面存放指针,因此返回的指针类型应该是二级指针,这样就可以使用二级指针a指向每一个一级指针a[i](也可以写成*(a+i)),每个一级指针a[i]又分别指向内存中一块连续空间的首地址,所以在使用一次malloc。这样所谓的动态"二维数组"就创建完成。此时a[i][j]相当于是 *(*(p+i)+j) 注意这里与二维数组的去引用意思是不同的!
因为数组中的元素依次排列在内存的一块空间里,且数值上*board=board=board[0] = &board[0][0]=&board[0]=第一个元素的地址所以我们也可以这样访问二维数组里的每一个元素:
#include <stdio.h>
int main(void)
{
int i,j;
char board[3][3] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'}
};
for(i = 0 ; i < 9; ++i)
printf(" board: %c\n",*(*board+i)); //board一定要加星号!*board相当于是*(board+0)=board[0]
return 0;
}
运行结果:
board[0][0]: 1 board[0][1]: 2 board[0][2]: 3
board[1][0]: 4 board[1][1]: 5 board[1][2]: 6
board[2][0]: 7 board[2][1]: 8 board[2][2]: 9