关于二维数组,二维数组指针

最近学习指针,一不小心就掉进了二维数组指针的坑里面,在迷惑了接近一个星期后,我有了以下的总结。(希望有大佬看见了能指点指点,我也不知道这么理解到底对不对,虽然我觉得是对的)

这是我一开始犯的错误,完全忘记了野指针这回事:

#include<stdio.h>
#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<stdio.h>
#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<N;j++)
        {
            printf("%d  ",*(*(p+i)+j));
        }
        printf("\n");
    }
}

输出:

关于参数传递:

//有这两种形式
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<N;j++)
        {
            printf("%d  ",*(*(p+i)+j));    //这是什么?
        }
        printf("\n");
    }
}

二维数组的输出有多种形式,最常见最不容易搞错的就是老老实实

printf("%d",a[i][j]);

但我都困惑这么久了,总不可能只用着一个方法吧,学了这么久总得用上!

于是来看地址:

#include<stdio.h>
#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<stdio.h>
#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<N1;i++)
    {
        for(j=0;j<N2;j++)
        {
            *(*(p+i)+j)=*(*(a+i)+j);
        }
    }
}

void show(int (*p)[N2])
{
    int i;
    int j;
    for(i=0;i<N1;i++)
    {
        for(j=0;j<N2;j++)
        {
            printf("%d  ",*(*(p+i)+j));
        }
        printf("\n");
    }
}

下面是一段总结,方便理解:

(网友:尘落曦枫  总结)

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个元素

  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值