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

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

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

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

 

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

程序1:spa

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 **设计

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

程序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;
}

输出结果:code

为啥能够输出结果呢:纯属巧合!!!!!htm

什么巧合呢:在个人机器上指针的长度和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的图

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

相关文章
相关标签/搜索