你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C进阶技巧——二级指针问题

[复制链接]
gaosmile 发布时间:2020-8-20 22:02
1、先把问题摆出来

9 W% m) ~3 E( Y8 I( ~/ I- c) G
参考Demo:
1#include <stdio.h>
3 D2 \7 E0 y) z 2#include <stdlib.h>4 t2 h- k% b( {& C$ S
3* D  n  j# k3 E2 f9 l- }& Q
4/************************************9 J# i& _6 J. b, l. E- {
5 * Fuction: 测试demo
+ r# o+ V3 b' |; q. b: g! O/ E8 h7 g 6 * Author :(公众号:最后一个bug)
8 W! M/ ~9 L" O7 K% V9 ]7 x0 V2 s 7 ***********************************/
- p4 D. D( @  F* W) N, ~4 [ 8int main(int argc, char *argv[]) {7 R8 X% v2 o1 q( {( y
9    int a = 10;
: w: R# B7 u  i! X3 g6 W( _  i10    int *ptr = &a;+ d* j2 K. Q( ]* B
11    int **ptrptr = &ptr;7 H+ Q" N2 y# A. o
12& E9 H* ~% L" f* T; L' i$ `: U6 z
13    printf("           *ptr = %d\n",*ptr);
7 r% h( i4 R& w% G% |: [# @8 v, Q14    printf("       **ptrptr = %d\n",**ptrptr);
6 Y8 t) y7 D- m: M15    printf("**((int **)ptr) = %d\n",**((int **)ptr));
5 n, L" Z" @* u6 D+ M16    printf("欢迎关注公众号:最后一个bug\n"); ' H/ n0 r  H* e. |+ \
17    return 0;
. G+ y$ a8 l1 U- ?2 n18}
9 t; }4 x5 Q6 H/ o
运行结果:
微信图片_20200820215607.png
现象描述:
  • 大家可以看到当试图输出**((int **)ptr)的时候程序奔溃了,其实在bug菌刚开始学习C的时候也是遇到了这个问题,最终理解清楚了就自然明白了。粗暴点就把((int **)ptr);*((int **)ptr);**((int **)ptr)都尝试着打印出来分析分析。
  • 所以bug菌在下面把指针的一些知识点都跟大家讲解一下,形成系统的知识,避免一些小伙伴仅学习了一些碎片而一知半解。- G( @1 T/ R/ E- X' t' t5 r% @) B4 i; }
      Y& X5 H; g+ z, J- V. ~
& B- f9 q) N. u% V: ^
2、二级指针的使用

8 d3 _# l: m$ I( t# h% U( V
1
多级指针
    其实多级指针在嵌入式程序中的应用还是相对比较少的,超过3级的bug菌仅仅只在一个特殊的索引功能里面使用过。    这里重点看看一、二级,毕竟二级指针与我们的二维数据结合使用,二维素组在图形、矩阵、算法等等方面还是使用非常广泛的。
2
一级指针
    指针其实广义的讲它也是一种数据类型,所以所谓的int* ptr;其中int* 就是变量ptr的类型,那么ptr就是我们常说的指针变量。
Demo:
1#include <stdio.h>
4 A5 ^* o! m/ Q3 `( b 2#include <stdlib.h>) D* k% H' Y! X: X
3/************************************6 R. `, ^6 e: d
4 * Fuction: 测试demo 9 T7 S' {: e. @% Q! n% R
5 * Author :(公众号:最后一个bug) 2 b* F+ V$ `! z1 U, b
6 ***********************************/( _$ b& e! H8 a& |( G% v% c
7int main(int argc, char *argv[]) {) M# e5 _: _- v7 g# I2 |
8    int a = 10;+ I8 J* [3 X/ \/ Z
9    int *ptr = &a;% k0 [9 h( ^" C( s# `( f9 K$ a; |- L
10
6 O: R! m8 I3 ?. |11    printf(" a   = %d\n",a);
) [8 ?" A, J$ C( Y% {6 }# z12    printf("&ptr = 0x%X\n",&ptr);, L& }. K5 v% E
13    printf("&a   = 0x%X\n",&a);
9 V3 C0 z( W) h. v14    printf("ptr  = 0x%X\n",ptr);
( s# @$ W6 }" A/ O15    printf("*ptr = %d\n",*ptr);& u3 P# R. Q5 N! o0 C
16
" j1 |9 }- z+ G! x& R1 V17    printf("欢迎关注公众号:最后一个bug\n");
% o2 v+ q0 I. z, v3 v18    return 0;! D* q/ j% \: s0 z" O
19}
运行结果:
微信图片_20200820215610.png
图解:
微信图片_20200820215613.png
分析一下:
  • ptr既然是变量,变量存于内存中,那么就一定有其地址,如上图所示ptr位于0x28FEE8地址处,其中其ptr里面保存的就是蓝色区域中的地址,也就是a变量所在的地址,所以&a与ptr是相等的。
  • *ptr就很好理解了,你可以把*ptr看成一个变量,其类型为int,其变量位于ptr值所在的内存地址处,即0x28FEEC处的int变量与定义的int a刚好一致。
    " \% }5 s6 N# V
3
二级指针
    如果大家已经理解了一级指针,二级指针也就顺理成章了,来看看下面的小程序:
Demo:
1#include <stdio.h>. J+ f- S7 H/ k$ A. K6 c
2#include <stdlib.h>
# @& Q( F1 `: `$ O, X 3/************************************+ A% Z& W9 r$ L; ^; E
4 * Fuction: 测试demo
3 n( ]# K. t  [/ ~+ t3 d4 q 5 * Author :(公众号:最后一个bug)
  U9 y% G4 G2 E+ ^: K 6 ***********************************/+ Z1 }/ U$ l8 w8 c+ e
7int main(int argc, char *argv[]) {1 f+ p5 K8 N# p0 e! L: }
8    int a = 10;
7 V9 g) c; X/ C% j0 |# P: x: H3 q 9    int *ptr = &a;+ k1 H( X' t9 U' U# L8 n: b/ N
10    int **ptrptr = &ptr;
8 \& K( \+ C9 h113 E; S* k8 p  }0 h! D
12    printf(" a      = %d\n",a);
9 F( Q' x5 f' x* D3 f/ ~13
% p5 j4 O/ w. S14    printf("&ptrptr = 0x%X\n",&ptrptr);, ^8 I# J$ J6 v# h
15) W9 g0 Y+ e+ o9 S1 h9 B
16    printf("ptrptr  = 0x%X\n",ptrptr);. R( j7 B( |- }3 w8 [3 k% C/ z
17    printf("&*ptrptr= 0x%X\n",&*ptrptr);! g+ H4 d4 D$ [% s/ y4 j, T
18    printf("&ptr    = 0x%X\n",&ptr);0 S3 W+ B9 y' b7 K
19
" K/ ^4 n9 Z+ {& R  W/ r20    printf("*ptrptr = 0x%X\n",*ptrptr);
* N- |. w) i1 I% \( ^8 y21    printf("ptr     = 0x%X\n",ptr);3 ?4 G. ?0 L9 S3 C; r% ~
22% x3 o! `" c  U4 S0 t
23    printf("*ptr    = %d\n",*ptr);
! O3 |! Y1 U' b# Q/ E) u24    printf("**ptrptr= %d\n",**ptrptr);8 l6 H5 u/ e. p' ^
251 U/ z0 ~6 y6 ~; T- m# N, H
26    printf("欢迎关注公众号:最后一个bug\n"); " a  K5 _: B4 G
27    return 0;2 x4 K. q! Z, Z9 C, C( ^1 d; r# j
28}
运行结果:
微信图片_20200820215616.png
图解:
微信图片_20200820215620.png
分析一下:
  • 通过上图来看ptrptr也是一个变量,其类型为int**,变量肯定有内存,其地址就是0x28FEE4,其变量保存的值是0x28FEE8(即ptr的地址)。
  • 那么*ptrptr,同样跟一级指针一致,把*ptrptr看成一个变量,也就是在ptrptr的值0x28FEEC8地址处的一个int*类型的变量,且该变量的值是0x28FEEC,其自身的地址为0x28FEE8。
  • 同样对于**ptrptr也看成变量,也就是*ptrptr的值0x28FEEC地址处的一个int类型的变量,那么此时该变量与a是相等的。
  • 最后在解释一下&*ptrptr,由于*ptrptr一个变量,&*ptrptr表示该变量的地址即0x28FEE8,然而该值刚好也是ptrptr变量的值,所以&*ptrptr = ptrptr。
    ' T0 n8 ~, c& {! N: A; h
$ s/ j1 u5 b( y/ u! z& L3 m
3、是时候解答前面的问题了# m! y+ V% H! {
参考Demo:
1#include <stdio.h>
! W1 `* E2 S6 o) l 2#include <stdlib.h># R# B5 [1 u/ {: H) u4 |
3
& |( f# Y) b; F1 K; M% L. \/ [& \: r) A 4/************************************  H7 ^* c9 O9 A8 U  y; v9 V
5 * Fuction: 测试demo
1 r5 A4 _# D3 U6 D 6 * Author :(公众号:最后一个bug)
- r( M: B! \$ P0 M" h2 ]  c 7 ***********************************/
2 P. S& ]1 a7 D$ z 8int main(int argc, char *argv[]) {
. y3 ^8 K% n& B1 X; V. k6 m  T) X 9    int a = 10;
" T: e5 M. k+ f" ^10    int *ptr = &a;
& m- s0 {# {& e+ q11    int **ptrptr = &ptr;
4 b( i9 g3 M  @' E3 w# f1 D* G122 H6 _: U" o! w7 z9 [; L
13    printf("           *ptr = %d\n",*ptr);
1 G# M8 Y  s; y9 X, x  \, H14    printf("       **ptrptr = %d\n",**ptrptr);
1 O! \4 y& o4 M+ b5 @15    printf("**((int **)ptr) = %d\n",**((int **)ptr));
* \# T% V7 K8 b; d' v16    printf("欢迎关注公众号:最后一个bug\n"); 3 g0 q/ Z. p, @) ]8 `
17    return 0;
1 R- C0 H6 e! @1 Z18}4 K. |$ ~. ~$ x( a3 w
分析一下:
  • 我们知道问题出在**(int**)ptr,不太理解的小伙伴总是觉得,我已经强制类型转化为二级指针了,前面只需要用**获得最后的值即可,怎么就不行呢? 我知道这里有问题我就是不理解为什么?
  • 那我们一起通过前面的知识来分析分析。同样把ptr看成是变量,变量的值并不会跟随强制类型而发生改变。强制类型仅仅只是改变了获取内存中数据的方式,并没有改变内存中的数据。下面图解一下:/ ]4 E- Z5 @3 _
    3 N7 `/ T) v+ W0 l' D
9 x( M/ u0 x2 {% H4 c. R5 v
微信图片_20200820215623.png
  • 所以本例子中对于强制类型转化中的**(int*****)ptr,无论强制类型转化为几级指针都没有丝毫意义,因为变量本身的值没有发生变化!所以强制类型转化以后第二个*便会指向出问题,从而导致访问了不正确的内存空间而程序奔溃。
  • 多级指针强制类型转化的目的大部分都是为了满足编译器检查指针层级操作逻辑是否有误。
  • 以后大家对于多级指针的分析不太熟练的话可以跟bug菌一样画画图分析分析,基本上一些理解上的问题就迎刃而解了。
    + o& v& S" V( K

0 Y, i0 {6 n8 I5 j3 h( Q7 L
4、最后小结5 G: h  C. a6 q0 X1 i6 d
4 O" |4 i' I$ E+ m/ L" d  p
    指针的理解就为大家讲解到这里了,如果你对指针还有畏惧感,那就只有一个可能,使用得太少了,多加练习自然生巧!

, l# R7 U$ ]: O5 S$ v$ F7 Q7 \
赞 收藏 1 评论0 发布时间:2020-8-20 22:02

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版