查看原文
其他

【C进阶】二级指针这个问题被问好几遍!该终结了!

bug菌 最后一个bug 2022-07-15


1、聊一聊

    今天推荐的bgm对于玩过魔兽的小伙伴应该非常怀恋吧,还记得那些"为了部落,为了联盟,永不为奴"的兽人吗?

    因为最近有几个小伙伴问到了同一个关于二级指针容易混淆的点,记得之前也有回答过其他小伙伴,所以这里bug菌就总结一下供大家学习参考。

2、先把问题摆出来

参考Demo:
1#include <stdio.h>
2#include <stdlib.h>
3
4/************************************
5 * Fuction: 测试demo 
6 * Author :(公众号:最后一个bug) 
7 ***********************************/

8int main(int argc, char *argv[]) {
9    int a = 10;
10    int *ptr = &a;
11    int **ptrptr = &ptr;
12
13    printf("           *ptr = %d\n",*ptr);
14    printf("       **ptrptr = %d\n",**ptrptr);
15    printf("**((int **)ptr) = %d\n",**((int **)ptr));
16    printf("欢迎关注公众号:最后一个bug\n"); 
17    return 0;
18}
运行结果:

现象描述:
  • 大家可以看到当试图输出**((int **)ptr)的时候程序奔溃了,其实在bug菌刚开始学习C的时候也是遇到了这个问题,最终理解清楚了就自然明白了。粗暴点就把((int **)ptr);*((int **)ptr);**((int **)ptr)都尝试着打印出来分析分析。

  • 所以bug菌在下面把指针的一些知识点都跟大家讲解一下,形成系统的知识,避免一些小伙伴仅学习了一些碎片而一知半解。


3、二级指针的使用

1

多级指针
    其实多级指针在嵌入式程序中的应用还是相对比较少的,超过3级的bug菌仅仅只在一个特殊的索引功能里面使用过。
    这里重点看看一、二级,毕竟二级指针与我们的二维数据结合使用,二维素组在图形、矩阵、算法等等方面还是使用非常广泛的。

2

一级指针
    指针其实广义的讲它也是一种数据类型,所以所谓的int* ptr;其中int* 就是变量ptr的类型,那么ptr就是我们常说的指针变量
Demo:
1#include <stdio.h>
2#include <stdlib.h>
3/************************************
4 * Fuction: 测试demo 
5 * Author :(公众号:最后一个bug) 
6 ***********************************/

7int main(int argc, char *argv[]) {
8    int a = 10;
9    int *ptr = &a;
10
11    printf(" a   = %d\n",a);
12    printf("&ptr = 0x%X\n",&ptr);
13    printf("&a   = 0x%X\n",&a);
14    printf("ptr  = 0x%X\n",ptr);
15    printf("*ptr = %d\n",*ptr);
16
17    printf("欢迎关注公众号:最后一个bug\n"); 
18    return 0;
19}
运行结果:

图解:

分析一下:
  • ptr既然是变量,变量存于内存中,那么就一定有其地址,如上图所示ptr位于0x28FEE8地址处,其中其ptr里面保存的就是蓝色区域中的地址,也就是a变量所在的地址,所以&a与ptr是相等的。

  • *ptr就很好理解了,你可以把*ptr看成一个变量,其类型为int,其变量位于ptr值所在的内存地址处,即0x28FEEC处的int变量与定义的int a刚好一致。

3

二级指针
    如果大家已经理解了一级指针,二级指针也就顺理成章了,来看看下面的小程序:
Demo:
1#include <stdio.h>
2#include <stdlib.h>
3/************************************
4 * Fuction: 测试demo 
5 * Author :(公众号:最后一个bug) 
6 ***********************************/

7int main(int argc, char *argv[]) {
8    int a = 10;
9    int *ptr = &a;
10    int **ptrptr = &ptr;
11
12    printf(" a      = %d\n",a);
13
14    printf("&ptrptr = 0x%X\n",&ptrptr);
15
16    printf("ptrptr  = 0x%X\n",ptrptr);
17    printf("&*ptrptr= 0x%X\n",&*ptrptr);
18    printf("&ptr    = 0x%X\n",&ptr);
19
20    printf("*ptrptr = 0x%X\n",*ptrptr);
21    printf("ptr     = 0x%X\n",ptr);
22
23    printf("*ptr    = %d\n",*ptr);
24    printf("**ptrptr= %d\n",**ptrptr);
25
26    printf("欢迎关注公众号:最后一个bug\n"); 
27    return 0;
28}
运行结果:

图解:

分析一下:
  • 通过上图来看ptrptr也是一个变量,其类型为int**,变量肯定有内存,其地址就是0x28FEE4,其变量保存的值是0x28FEE8(即ptr的地址)。

  • 那么*ptrptr,同样跟一级指针一致,把*ptrptr看成一个变量也就是在ptrptr的值0x28FEEC8地址处的一个int*类型的变量,且该变量的值是0x28FEEC,其自身的地址为0x28FEE8。

  • 同样对于**ptrptr也看成变量,也就是*ptrptr的值0x28FEEC地址处的一个int类型的变量,那么此时该变量与a是相等的。

  • 最后在解释一下&*ptrptr,由于*ptrptr一个变量,&*ptrptr表示该变量的地址即0x28FEE8,然而该值刚好也是ptrptr变量的值,所以&*ptrptr = ptrptr。


4、是时候解答前面的问题了

参考Demo:
1#include <stdio.h>
2#include <stdlib.h>
3
4/************************************
5 * Fuction: 测试demo 
6 * Author :(公众号:最后一个bug) 
7 ***********************************/

8int main(int argc, char *argv[]) {
9    int a = 10;
10    int *ptr = &a;
11    int **ptrptr = &ptr;
12
13    printf("           *ptr = %d\n",*ptr);
14    printf("       **ptrptr = %d\n",**ptrptr);
15    printf("**((int **)ptr) = %d\n",**((int **)ptr));
16    printf("欢迎关注公众号:最后一个bug\n"); 
17    return 0;
18}
分析一下:
  • 我们知道问题出在**(int**)ptr,不太理解的小伙伴总是觉得,我已经强制类型转化为二级指针了,前面只需要用**获得最后的值即可,怎么就不行呢? 我知道这里有问题我就是不理解为什么?

  • 那我们一起通过前面的知识来分析分析。同样把ptr看成是变量变量的值并不会跟随强制类型而发生改变。强制类型仅仅只是改变了获取内存中数据的方式,并没有改变内存中的数据。下面图解一下:


  • 所以本例子中对于强制类型转化中的**(int*****)ptr,无论强制类型转化为几级指针都没有丝毫意义,因为变量本身的值没有发生变化!所以强制类型转化以后第二个*便会指向出问题,从而导致访问了不正确的内存空间而程序奔溃。

  • 多级指针强制类型转化的目的大部分都是为了满足编译器检查指针层级操作逻辑是否有误。

  • 以后大家对于多级指针的分析不太熟练的话可以跟bug菌一样画画图分析分析,基本上一些理解上的问题就迎刃而解了。


5、最后小结

    指针的理解就为大家讲解到这里了,如果你对指针还有畏惧感,那就只有一个可能,使用得太少了,多加练习自然生巧!

    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!

   如果有想加入公众号群聊共同讨论技术的小伙伴可以添加下方bug菌微信

推荐好文  点击蓝色字体即可跳转

【收藏】get这些技巧,HardFault_Handler排查只需要几分钟

【C进阶】这种地方别再强制类型转化了,来告诉你个小技巧!

【算法】"暴力"字符匹配算法的C语言实现

【重磅】剖析MCU的IAP升级软件设计(设计思路篇)

【算法】高效"KMP"字符匹配算法就这么简单

【典藏】自制小型GUI界面框架(设计思想篇)

【C进阶】听说用 “ 逗号表达式 ” 仅仅为了秀技?

深度剖析"bit序"与"字节序"

【进阶】嵌入式编程技法之"数据驱动编程"

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存