关于指针数组与数组指针的理解

上一篇介绍了指针和数组的区别和联系,相信很多同学都已经明白了指针和数组的用法,那么如果指针和数组混合起来,你还会用吗?

指针数组

指针数组是一个数组,它里面存储的是指针变量。比如说 int *p[5],数组里面有五个元素,里面存储的是指针。由于[]*的优先级要高,故 p 先与[]结合,也就是说 p 是一个数组。

数组指针

数组指针是一个指针,它在32位机器下占四个字节大小,64位机器下占据八个字节。比如int (*p)[5],表示指向拥有5个元素的数组,示例:

int main()
{
    int a[3][5] = {0};
    int (*p)[5] = a;
}

需要注意的是,数组指针后面括号里面的数字必须与二维数组的列数相同才可以。

地址偏移量

地址偏移量的概念不太好理解,为了便于理解,我们引入房间地址楼层地址这两个概念。

在一维数组中,比如int a[5]; a 代表的是一个房间地址,那么 a+1 就会偏移一个房间地址的距离(以数组中的一个元素所占内存字节为单位进行地址偏移),也就是偏移到 a[1] 的地方。

&a 代表的是一个楼层地址&a+1 会偏移整个数组的长度(以整个数组所占内存字节为单位进行偏移),也就是偏移到了整个数组后面的地方。

指针数组操作二维数组

int main()
{
    //指针数组操作二维数组
    int a[4][5]; //定义一个二维数组
    int i, j;
    int *p[4]; //定义一个指针数组(是个数组),和二维数组的行数相同。

    //初始化二维数组
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            a[i][j] = 10 * i + j;
        }
    }

    //输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("a[%d][%d]= %d\t", i, j, a[i][j]);
        }
    }
    printf("\n\n");

    p[0] = *a; //指针数组(数组),存储的是"房间"的地址,而不是"楼层"的地址,如果这样写p[0] = a;这样在c++中编译不通过的
    p[1] = *(a + 1); //给第二个元素赋值
    p[2] = *(a + 2); //给第三个元素赋值
    p[3] = *(a + 3); //给第四个元素赋值

    //第一种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("p[%d][%d]= %d\t", i, j, p[i][j]);
        }
    }
    printf("\n\n");


    //第二种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(*(p+%d)+%d)= %d\t",i ,j, *(*(p + i) + j));
         }
    }
    printf("\n\n");

    //第三种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(p[%d]+%d)= %d\t", i, j, *(p[i] + j));
        }
    }
    return 0;
}

输出结果:


指针数组运行结果

解释:
p 数组里面存放的是一级指针,p[0] 保存的是二维数组第一层楼第一个房间地址,p[1] 保存的是二维数组第二层楼的第一个房间地址,p[2] 保存的是第三层楼的第一个房间地址,p[3] 保存的是二维数组第四层楼的第一个房间地址;之后,p[0][0] 表示:(p[0])[0] == (p 数组的第一个元素)[0] == (*a)[0] == (a[0])[0] == a[0][0],其他的以此类推,得出结果。

数组指针操作二维数组

int main()
{
    //数组指针操作二维数组
    int a[4][5]; //定义一个二维数组
    int i, j;
    int (*p)[5]; //定义一个数组指针(是个指针),和二维数组的行数相同

    //初始化二维数组
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            a[i][j] = 10 * i + j;
         }
    }

    //输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("a[%d][%d]= %d\t", i, j, a[i][j]);
        }
    }
    printf("\n\n");

    p = a; //让指针指向二维数组

    // p = *a; //虽然a和*a的值都是一样的,但是这样无法赋值(a是"楼层地址",*a是"房间地址")

    //第一种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("p[%d][%d]= %d\t", i, j, p[i][j]);
        }
    }
    printf("\n\n");


    //第二种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(*(p+%d)+%d)= %d\t",i, j, *(*(p + i) + j));
        }
    }
    printf("\n\n");

    //第三种方式输出二维数组内容
    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(p[%d]+%d)= %d\t",i, j, *(p[i] + j));
        }
    }
    return 0;
}

输出结果:


数组指针运行结果

解释:
p 里面存放的是一维数组的地址(注意不是数组首元素的地址,是整个数组的地址),在程序中 a 表示的就是第一层楼的地址,也就是 &a[0] 。由于 p 指向的是楼层地址,则 p+1 则表示第二层楼的地址,p+2 表示第三层楼的地址...当我们用 p[0][0] 的时候,其实表示的就是第一层楼的第一个房间内容(p 表示的第一层楼的地址,p[0] 表示的第一层楼的第一个房间的地址,p[0][0] 表示的第一层楼的第一个房间的内容),其他的以此类推。

总结

  1. 指针数组是数组,数组指针是指针;它们符合各自数组或指针的特性;
  2. 数组和指针都是操作地址的运算;
  3. 地址也是有级别的,例如上面所说的楼层地址房间地址(本质是地址操作时候的偏移单位不同);
  4. 很重要的一点,数组的地址是连续的!!上面的操作都是基于这点才可以实现的,如果换成链表,则上面程序的输出结果将无法判断;
  5. 上面提到的指针数组和数组指针都属于二级指针范畴,如果是int ****p[5],你还能操作二维数组吗?换成三维数组呢?抓住本质,无论多少级都一样操作。

补充

与指针数组和数组指针类似的还有一个:二级指针,示例:

int main() 
{
    int a[4][5]; 
    int i, j;
    int *q[4]; 
    int **p;

    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            a[i][j] = 10 * i + j;
        }
    }

    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("a[%d][%d]= %d\t", i, j, a[i][j]);
        }
    }
    printf("\n\n");

    q[0] = *a; 
    q[1] = *(a + 1); 
    q[2] = *(a + 2); 
    q[3] = *(a + 3); 
    p = q;

    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("p[%d][%d]= %d\t", i, j, p[i][j]);
        }
    }
    printf("\n\n");


    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(*(p+%d)+%d)= %d\t",i ,j, *(*(p + i) + j));
        }
    }
    printf("\n\n");

    for(i = 0; i < 4; i++) 
    {
        for(j = 0; j < 5; j++)
        {
            printf("*(p[%d]+%d)= %d\t", i, j, *(p[i] + j));
        }
    }
    return 0;
}

自己输出一下结果,尝试理解一下指针的工作原理,相信你可以征服它!!!

练习

int a[] = {0, 2,4,6,8};
int *p[5]={a, a+1, a+2, a+3, a+4};
int ** pp = p;
int main()
{
    printf("%d\n",*pp++);
    printf("%d\n", *pp-a);
    printf("%d\n", ** ++ pp);
    printf("%d\n", pp - p);
    return 0;
}

输出结果是什么呢?

#include <stdio.h>

int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *)(&a + 1);
    printf("%d %d\n", *(a+1), *(ptr-1));
    return 0;
}

输出结果是什么呢?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,419评论 3 44
  • 变量的声明和定义变量声明(declaration) 可以declaration很多次,不占内存空间,例如 exte...
    FlyingReganMian阅读 1,015评论 0 1
  • 前言 最近真的是忙的不可开交,公司一直给安排任务,连学习和写笔记的时间都没有了,落下好几次课的笔记都没有写,所以我...
    Xiho丶阅读 1,503评论 1 12
  • 文/阿霞 忙 早上7点,园区的饭堂已经热闹起...
    深圳阿霞阅读 505评论 2 5
  • 从昨天回了家以后,接俩个电话,录了一个电台。我都没有说过一句话。这算我活了这么多年第一次感到绝望吧。夜很漫长,我睡...
    Joey冰阅读 372评论 2 5