首页 > 代码库 > 二维数组和二级指针(真的没什么关系)

二维数组和二级指针(真的没什么关系)

刚开始学c语言的时候,总是会认为,一级指针可以用来访问一维数组,那么二维数组就要用二级指针来访问啦。。。。

实际上二级指针和二维数组真的没什么关系,而且,切记千万不要用二级指针访问二维数组。。。。。

下面是几个有关的小程序,加深印象。。。。。。。。

 

实验环境:主机CPU酷睿i5,vs2012

程序1:

int _tmain(int argc, _TCHAR* argv[])
{
    int **p= NULL;
    int a[2][3] = {1,2,3,4};
    p = a;
    return 0;
}

结果:编译错误,错误提示:无法从“int [2][3]”转换为“int **

可见,二级指针和二维数组名,根本就不是一类东西。

程序2:

int _tmain(int argc, _TCHAR* argv[])
{
    int **p= NULL;
    int a[2][3] = {1,2,3,4};
    p = (int **)a;
    printf("指针的长度为:%d\n",sizeof(p));
    printf("值为:%d\n",(int)(*p));
    p++;
    printf("值为:%d\n",(int)(*p));
    getchar();
    return 0;
}

输出结果:

技术分享

为啥可以输出结果呢:纯属巧合!!!!!

什么巧合呢:在我的机器上指针的长度和int类型的长度都刚好为4个字节。

 

把程序放在虚拟机中跑一下,虚拟机的系统是CentOS7,64位的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值为:%d\n",(int)(*p));
    p++;
    printf("值为:%d\n",(int)(*p));


    char *pointer;
    printf("指针的长度为:%zd\n",sizeof(pointer));
    
    return 0;
}

结果:编译错误,提示:

技术分享

原因是,在我的虚拟机中指针占8个字节吗,而int占四个字节。

但是long是占8个字节,所以改成long也可以实现主机中的效果。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    long a[2][2]={1,2,3,4};


    long **p =(long **)a;
    printf("值为:%ld\n",(long)(*p));
    p++;
    printf("值为:%ld\n",(long)(*p));


    char *pointer;
    printf("指针的长度为:%zd\n",sizeof(pointer));
    
    return 0;
}

结果为:

技术分享

原因和第一个程序一样,纯属巧合:在我的虚拟机中指针和long都占8个字节。

在写这个程序的时候还有个小插曲(小错误),也设计了两个知识点,顺便分享一下,写上面程序的时候。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值为:%d\n",(long)(*p));
    p++;
    printf("值为:%d\n",(long)(*p));


    char *pointer;
    printf("指针的长度为:%zd\n",sizeof(pointer));
    
    return 0;
}

输出结果为:

技术分享

在输出long型数据的时候我不小心用了%d,而不是%ld。

看一下用%ld的效果:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值为:%ld\n",(long)(*p));
    p++;
    printf("值为:%ld\n",(long)(*p));


    char *pointer;
    printf("指针的长度为:%zd\n",sizeof(pointer));
    
    return 0;
}

输出结果为:

技术分享

为什么会这样?  还是要从内存角度看:

在我的虚拟机中,指针占8个字节,而p是个二级指针,*p就是个int类型的指针,占8个字节,所以其实*p占据了a[0]和a[1]。

至于为什么结果是8589934593.这还要涉及一个字节序的问题(这里就不解释了)

我的cpu是英特尔的,一般x86系列的cpu都是采用低字节序。

所以a[0]和a[1]两个单元在内存中类似于:

高地址------------------------------------------------------------------------------------低地址

00000000  00000000  00000000 00000010     00000000 00000000 00000000 00000001

把这段内存解释成long类型的数据就是8589934593

 

------------------------------------------------------------------------------------------------------------------------------

还要注意的是我上面,那两个巧合之下能运行的程序,都是用*p访问的,如果用**p会报错,因为**p就是*p指向的内存空间的值,而*p指向的内存,也就是8589934593地址空间,是未知的。

总之记住,二级指针和二维数据没啥关系

 

 

问题来了,既然不能用二级指针访问二维数据,那怎样用指针访问二维数组呢?

在我之前的随笔 由typedef和函数指针引起的危机  中,提到了,要声明某种类型的指针变量,只需先声明处该类型的变量,然后加上*即可(注意优先级)

那么怎样用指针访问二维数组呢?

先来回忆一下怎样用指针访问一维数组。在访问一位数组时,我们实际上声明的是一个和数组元素类型相同的指针变量指向了数组第一个元素的地址,然后在用这个指针访问数组。

比如访问int b[3]= {1,2,3}.

b中的元素为int类型,所以我们要声明一个int类型的指针变量 如int *p ,然后将p指向b的第一个元素的地址,即p = &b[0],数组的首地址和第一个元素的地址是一样的,所以也可以用p=b;

这里需要强调的是,指针类型和数组元素的类型一致,而不是数组类型一致,比如b的类型是有三个int类型元素的数组,而b中元素是int类型,b是数组类型,而元素是int类型,是不一样的。上面之所以能够用p=b,不是说p是数组类型的指针,只是数组的首地址,和数组中第一个元素的地址一样罢了p是个int类型的指针而不是数组类型的指针,这一点一定要记住。。。。

 

回到二维数组来,拿int a[2][3]= {1,2,3,4,5,6}来说, 数组a的元素为 一个含有三个int类型数据的数据,即a的元素是一个一维数组,这个数组含3个元素。。。。

那么怎样声明指向a数组中元素的指针变量呢? 在 由typedef和函数指针引起的危机  提到,方法及时先声明一个该类型的变量,然后加上*即可,

a中元素为含有3个int数据的数组,定义这样一个普通变量为: int p[3],然后在变量名前面加上*即可,但是要注意运算符的优先级,因为*的优先级比[]低,所以要加括号,即int (*p)[3]。

这样再将p指向a的第一个元素的地址:p = &a[0],然后就可以用p来访问数组a啦

给出程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][3] = {1,2,3,4,5,6};
    int (*p)[3] = &a[0];
    printf("值为:%d\n",(*p)[0]);
    printf("值为:%d\n",(*p)[1]);
    printf("值为:%d\n",(*p)[2]);
    p++;
    printf("值为:%d\n",(*p)[0]);
    printf("值为:%d\n",(*p)[1]);
    printf("值为:%d\n",(*p)[2]);
    getchar();
    return 0;
}

 

结果为:

技术分享

 

再来一个程序,加深一下理解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][3][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
    int (*p)[3][4] = &a[0];
    int i = 0;
    for(;i < 3; i++)
    {
        int j = 0;
        for(; j < 4;j++)
            printf("值为:%d\n",(*p)[i][j]);

    }
    p++;
    i = 0;
    for(;i < 3; i++)
    {
        int j = 0;
        for(; j < 4;j++)
            printf("值为:%d\n",(*p)[i][j]);

    }
    return 0;
}

运行结果:

技术分享

 

 

 最后,贴上一张,来自csdn的图

技术分享

希望对你有帮助,有纰漏的地方还请指正,谢谢。。。。

 

二维数组和二级指针(真的没什么关系)