最近学习指针,一不小心就掉进了二维数组指针的坑里面,在迷惑了接近一个星期后,我有了以下的总结。(希望有大佬看见了能指点指点,我也不知道这么理解到底对不对,虽然我觉得是对的)
这是我一开始犯的错误,完全忘记了野指针这回事:
#include
#define N 3
int main(void)
{
int (*a)[N]= //不能这么做,这是一个二维数组指针,指针指向的是一个二维数组,定义一个指针需要有地址,这样写有些编译器都通不过
{
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15},
};
}
正确的操作方法如下:
#include
#define N 5
void show(int (*p)[N]);
int main(void)
{
int a[][N]=
{
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15},
};
int (*p)[N]=a; //指向一个二维数组的指针。注意,在定义数组指针的时候必须要有()括号,*p[N]的意思是指针数组,p这个数组的每个元素都是一个int*。
//其根本原因在于*的计算优先度小于[]
show(p);
}
void show(int (*p)[N]) //参数的传递有多种方法,下面会帖出其他方法。
{
int i;
int j;
for(i=0;i<3;i++)
{
for(j=0;j
关于参数传递:
//有这两种形式
void show(int (*p)[N]); //进行参数传递时,列的个数必须是已知
void show(int p[][N]); //进行参数传递时,列的个数必须是已知
//你也可以省略形参名
void show(int (*)[N]);
void show(int [][N]);
其中
void show(int (*p)[N]);//p是一个指针,它指向了一个数组。(数组内部有4个int类型的值)
void show(int p[][N]); //空的[]表明p是一个指针,因此上下是等价的
关于二维数组的地址,以及指针的解引用
void show(int (*p)[N])
{
int i;
int j;
for(i=0;i<3;i++)
{
for(j=0;j
二维数组的输出有多种形式,最常见最不容易搞错的就是老老实实
printf("%d",a[i][j]);
但我都困惑这么久了,总不可能只用着一个方法吧,学了这么久总得用上!
于是来看地址:
#include
#define N 4
int main(void)
{
int i,j;
int a[][N]=
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
};
printf("%p\n",a);
printf("%p %p\n",&a[0],a[0]);
printf("%p\n",*a);
printf("%p\n",**a);
}
这是结果:
为什么输出a *a会是一个地址呢?后面这个**a又是什么鬼?
可以这么理解:把(*a)中的a看成一个行指针,它指向的是数组的行,而后面的[N]则指向了列。(要注意的是,这个N仅仅代表行的长度,如果你在运算的时候不慎使用了这个N,结果将会指向下一行!)
数组连续存放在地址中,这么画是因为看着方便,更容易理解
为什么*a和a和a[0]输出结果是一致的呢?(实际上的含义并不相同)
*a应该这么写:(*(a+0)+0) 代表第0行第0个元素的地址
a应该这么写:(a+0) 代表第0行的首地址,也就是所谓的行指针
a[0]代表第0行首元素地址
那么:
由此也可知,其实每一行的首地址都差了四个int也就是4*4=16的字节,移动行指针就会跳过后面的三个地址,指向下一行的首地址。
所以所谓的列指针,实际上是在首地址后的三个地址间移动!
三角形所指向的就是二维数组每一行的首地址
那么我们就可以这么理解了
*(a+0)指向的是一个数组,里面存放了四个地址,而改变a,就会指向另外一个存放了四个地址的数组,步长为4*4=16字节。需要这么写:*(a+i);
(*(a+0)+0)指向的是数组里的元素,也就是*a所含有的四个地址,改变二级指针,就会在这个一级指针的数组里移动,步长为4字节。需要这么写(*(a+i)+j);
它等价于
(*(a+i))[j];
代表他是第 i 行第 j 个数
所以**a就是*(*(a+0)+0),就是二维数组的值
下面是一个程序,通过参数传递来修改指针所指向的内容,从而把二维数组a的值赋给b
#include
#define N1 3
#define N2 5
void f(int (*a)[N2],int (*p)[N2]);
void show(int (*p)[N2]);
int main(void)
{
int a[N1][N2]=
{
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15},
};
int b[N1][N2];
int (*p)[N2]=b;
f(a,p);
show(b);
}
void f(int (*a)[N2],int (*p)[N2])
{
int i;
int j;
for(i=0;i
下面是一段总结,方便理解:
(网友:尘落曦枫 总结)
a代表0行地址
&a代表整个数组首地址 正好等于首行首地址
*a表示0行首地址
a+1代表第0+1行地址
**a首行首地址元素 (双重解引用:第一重确定首地址;第二重确定元素值)
*a代表第0行首地址
*(a+1)代表第0+1行首地址
*(a+2)代表第0+2行首地址
a[i]代表第i行元素首地址,等价于*(a+i)
a[i][j]
**a ==*(a[i]) 表示i行首地址元素,等价于 *(a+i)
a[0] == *a 表示0行首地址
&a代表整个数组的首地址
&a+1代表该数组下一个元素的下个位置的地址
*(a+i)+j 代表的是地i行第j个元素(也就是数组中的一个地址) *a+1代表第0行第1个元素
*(a+1)+1代表第1行第1个元素