QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2393|回复: 0
打印 上一主题 下一主题

C++数组指针、函数指针、成员函数指针

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-12 18:49 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    C++数组指针、函数指针、成员函数指针
    ' q# {& X3 K# Z5 BC++数组指针、函数指针、成员函数指针
    7 E6 J3 `% k9 m  M) n
    2 L  p) V4 g& M& X6 t+ ?' }1 \& ~4 H; d$ Z& ~- j; L
    操作符名称
    4 W3 b" N9 D0 B: S6 s2 r& 取地址符(Address-Of operator)  w6 x4 C1 r! j
    * 间接寻址运算符(Indirection operator)
    ( q' y) e/ U) v7 g! z) w.和-> 成员访问运算符(Member-Access operators),用于取对象的成员。
    4 s1 \+ ]8 R+ e( E' F2 R.*和->* 指向成员的指针运算符(Pointer-To-Member operators), 用于成员函数指针和成员变量指针的取对象。# x; b' |8 V7 m& Q% k. o
    () 函数调用运算符(Function-Call operator)
    " l7 c1 H% o9 f0 k9 z* S& x. f:: 范围解析运算符(Scope-Resolution operator)
    1 t3 d; a/ y% f3 c( t* k如何定义一个指针变量
    3 M/ n+ T2 M. W- J0 L. \! x假设类型T, 变量名称name, 指针的定义如下:) W, X0 O  T) G3 W8 ~4 v
    7 W- s& Q3 i" V
    T* name;1 F$ [+ {1 e! K: G! f( I9 q! Y
    标识变量名字name, 它是T类型的指针。例如
    6 K$ o3 K9 {/ f+ g2 a  j6 i
    4 y9 c2 M& K9 t1 U+ b5 T4 Y- Kint n = 0;# i3 b5 R5 |2 f/ `5 Z. i. |
    int* p_n = &n;
    : P) v9 f! r& g: c/ U2 xp_n是int指针类型, 指向某个int型的对象。5 i1 C* n) s1 E8 F
    . f' o# _$ ?1 \# p: u
    指针变量的修饰
    . H# N# G0 G8 ~) ?4 q2 M* Z指针实际上也是一种变量类型, 只是它保存的内容有些特别, 是指定类型的地址值,通过间接寻址运算符(indirection operator)*, 可以访问到指针指向地址上的指定类型。5 K, q1 R4 G4 ~0 K" N, e( H
    ( |1 U5 {1 n3 B5 P) X
    指针也可以用const, volatile修饰。 const int或int const均表示一个变量类型是int, 且该变量不能修改。以下两种写法都可以:
    : r* ]8 W0 X! H' K: D! S! V- o- j2 {4 \  Y  n, r9 q
    const int a = 1;
      }- b9 J! {- }: pint const b = 2;
    1 ~- S6 v4 Y" a/ S既然指针是也一种变量类型,同样支持被const修饰, 表示指针的值/指针的指向不允许修改, 指针所指向的那个变量是否允许修改, 那是另外修饰。写法如下:
    9 U3 s" `3 h" d$ H/ `; Z: g- L: v; d( X; X+ H- Y
    int a = 1;6 k) c) q( d! L( l+ y4 K( I
    int b = 2;
    2 [6 @- w8 Y  N( H0 M# cint* const cp_a = &a; // 指针的修饰词,放在*号后面。
    , z+ ~5 L7 Q" e+ s% v) d: W& U*cp_a = 10; // 指针指向的值可以修改4 b- G$ V; Q! a. o* }8 o
    cp_a = &b; // 指针不能被修改,报错!
    . k, F4 _( ^- ^" e2 w总结带修饰的指针的格式:
      `/ c/ U# G6 ^4 Z! N9 _" T只要记住修饰词总是放在被修饰的内容后面。
    4 l1 L2 e& o- `$ O/ z* e
    2 U6 U/ }. e% S, s& y6 t: wcv表示const / volatile修饰词。指针定义形式如下:
    : f% j" {5 @( v
    , d; u" `' K5 U4 v2 I6 lT [cv for T] * [cv for pointer] name
    $ v' g: K0 r( o注意对T的修饰放在T的前面也是合法的写法。
    8 X4 F4 M$ [% _* Q$ q) d2 V+ ?- y9 ?4 ~$ Q, Y( U0 F% E
    const int const c = 2;
    " t! c: q6 H3 P& I; @在mscv编译器下也不会报错。
    7 z- }2 F: ], ]& Z4 e9 O0 Z' n6 q- f3 X1 P! e2 a5 ?) |
    完整的格式:
    5 b: N+ ^* r7 |3 B* i/ m2 {[cv for T] T [cv for T] * [cv for pointer] name# J4 o- }; e) d. O
    / M6 u6 J! K: S5 h1 \) a
    Syntax        meaning: G$ k4 n- n. h) C- `; t( T3 y5 ~
    const T*        7 G; a3 [5 T: m/ l5 }
    pointer to constant object" F0 _! _! A3 f* F  ?& J

    ( _& @8 B( Z8 \2 R" rT const*        pointer to constant object" v& o- D6 }9 I( \5 M+ Y
    T* const        constant pointer to object
    & q& [( o# W, u* X( @7 gconst T* const        constant pointer to constant object2 ?, Z, R5 e, W) K: `1 b4 {1 g
    T const* const        constant pointer to constant object2 a" y+ W3 i# V7 _, n
    上面格式中T还可以是一种指针, 指针的指针仍然是按照修饰词总是修饰前面的标识(T或者*)来确定修饰的意图。
    $ p/ @6 |5 U' d4 X9 ?: F  A1 H, `) W6 L2 S
    int a = 1;) |- d: x- P. Y
    int b = 2;
      F4 p* }6 m* j9 Z4 b* u1 G3 r7 P, y- s  S& l5 x
    int* p_a = &a;
    % }& I4 _2 M4 M; p9 y) ?*p_a = 10; // 合法
    + v2 Y. U: T& ip_a = &b; //合法
    6 y# I4 t: G) W4 @0 O2 a
    $ s0 w' Q( `# ^: P0 o+ X# O& s3 Qconst int* cp_a = &a; // const修饰int类型, 并非修饰指针1 V' m% h3 W. ?! u
    *cp_a = 11; //报错! const int类型不能修改9 u6 [7 \. O* a: f3 B. k
    cp_a = &b; // 合法, 指针没有const修饰,指针可以修改。: ^# N* i! I' Y4 e& o, V+ V3 P  K

    ! S; u! d3 G* e- \6 {# R8 `int* const pc_a = &a; // const修饰指针。类型没有const修饰0 M6 M8 X& E! `% {/ I( l
    *pc_a = 12; // 合法, 因为类型没有const修饰,可以修改。1 |: ?6 a$ G, \$ z' }/ A
    pc_a = &b; //报错! 指针被const修饰, 不能修改指针。4 X- N6 v3 P, r! B+ M: D$ s7 A

    0 s4 }* o+ Y" o$ S) `int const* const cpc_a = &a; // int类型被它后面的const修饰, 指针符号*后面也有const修饰& z9 D" Q- v! v0 m" w
    *cpc_a = 13; // 报错! 类型被const修饰,不能修改。2 H! ~2 A$ F( H2 i3 S. \# u
    cpc_a = &b; // 报错! 指针被const修饰,不能修改。
    . o5 @3 O. I$ `+ ]2 ]$ @1 m
    ; d% n" y& R8 S4 h9 @& m( ?8 z 更复杂的指针的指针$ N4 q* S& k0 @% J
    - I6 r6 I# J% ^# {8 f; R
    int a = 1;
    * R* n/ o# A2 M# X* {" E$ I/ ?5 nint b = 2;/ T. z# x% E3 s3 w& t+ |9 B3 `) X
    int* p1 = &a;: F* f; S& j8 O
    int* p2 = &b;# }2 I/ H; R" s6 W
    const int* ct_p1 = &a; // ct for const type
    , `2 C2 F; M1 U% g0 g( S" Econst int* ct_p2 = &b; // ct for const type0 Y0 V4 V. r# H- \7 ]/ b7 L* e
    ) ~$ D  c; Y0 _) t
    // int * * pp1; 指向(int*)类型的指针
    0 }) S% S1 e3 E: K$ ^int** pp1 = &p1;  
    2 ~) p; L& \- V+ o' r% }4 n" [3 |) b" ~pp1 = &p2; // 合法, 2 x$ B; ]- h" U: W2 V
    pp1 = &ct_p1; // 报错! 类型不匹配。 (int*)不能指向(const int*)' ]! U0 [% E& B& U

    5 _3 n! V9 I; G; C0 T" w& g8 l// (const int) * * pp1; 指向((const int) *)类型的指针6 Q6 w& k% k$ i) i( m
    const int** ct_pp1 = &ct_p1;  
    2 s  J5 s9 k' c, C( ^" kct_pp1 = &ct_p2; // 合法; F. F6 Z0 M; i& ?
    ct_pp1 = &p1; // 合法!(const int*) 可以指向(int*)类型。
    & \( F* F9 o+ ]0 _' B4 v  x2 S; D4 ^% t0 _1 W# K
    // (const int) (*const)
    2 m1 B1 Y% y- u7 Rconst int * const ct_cp1 = &a; // 指针也不能修改4 Y6 D0 v+ \! ~& q6 }, }2 k% @" k
    const int * const ct_cp2 = &b; // 指针也不能修改
    " X" t; ]( f0 e. ^& @ct_cp1 = &b; // 报错!指针有const修饰
    & Z) e% G; {$ T# N' b4 q0 t4 R2 M/ w6 q: [) C
    // (const int) (* const) *  指向((const int) (*const))的指针
    & ^  S- k! I# t4 t5 x3 iconst int* const * ct_cp_p1 = &ct_p1;  
    / f1 w$ z' u0 s7 b4 T. [/ v9 ~. i7 bct_cp_p1 = &ct_cp2; // 合法, 指针的指针并没有const修饰, 指向的指针有const修饰. G. }, k9 j; u, w
    *ct_cp_p1 = &a; // 报错!等价于操作ct_cp2,  指向的指针是带const修饰的不能修改
    ; @( Y2 Q, O6 e+ w
    , T8 r6 e1 Q" k4 B. C6 J( j3 K// (const int) (* const) (*const)  * d" w2 G/ C# D; \  w* r& x% ]( }
    // 指向((const int) (*const))的指针,且该指针被const修饰$ q" Q+ M/ [4 _# l5 F
    const int* const * const ct_cp_cp1 = &ct_cp1; * `7 y8 |9 V- v6 h5 X
    ct_cp_cp1 = &ct_cp2; // 报错! 指针的指针被const修饰, 不能修改指针指向。
    * K, w$ p( j, y) _1 E, x. y( D' V( j( t0 H; |" m7 D
    一行声明多个变量
    1 B( b2 V+ l. \0 ]7 i3 Z: q类型 + 名称定义一个变量。8 g% r# }- H0 `; v" D
    变量的前面可以加*号修饰, 表示指针, 一个星号代表一层间接。**表示指针的指针。$ E; m6 S& i& f# G- f% X  F

    . [" L  k) ?( gint a, *b, *c, d, **e;" ?% `/ L* R6 k2 e  W6 E
    a = 0;
    3 Z3 H9 J6 S6 j3 R0 qd = 1;4 m" a  [+ D. ^* m
    b = &a;
    " h7 o  R- {$ pc = &d;' ?: [! f6 t9 {! a& {; X* @
    e = &b; // e为int**类型 指针的指针7 O; Y# ?' L4 H( |  f1 ?
    e = &c; // e为int**类型 指针的指针& U! k1 ~0 Z$ Y( E1 R
    也可以用括号包围变量和*号。; _! _- B! o  t' H+ B" I0 i
    & h# S& q& H0 u! n: W# V
    int (a), (*b), (*c), (d), (**e); // 合法定义。& `* G. F6 Y1 j1 V& F) }
    括号可以省略,某些情况, 个人感觉加上括号更清晰一些。例如  t& @: @( l) i! B7 N/ K) s$ O/ t' X
    # B0 b3 H3 t- w, @# c
    int (a), (const *b), (*const c) = &a, (const d), (const* const* const e) = &c;
    , O7 e! w% k$ X" d+ t0 H% Z写成3 Z7 ~( w+ `# [, [5 e- a
    ; B! O" X( n% z! ?0 q% r. @
    int a, const *b, *const c = &a, const d, const* const* const e = &c;  q# d6 Q0 W" E5 p0 d/ m# E
    更重要的是, 后面我们表达数组指针,以及函数指针时,括号是不可缺少的, 带括号的表达更加统一。. M; [4 O) t$ N+ l/ d& u5 ?
    8 j9 {9 @$ ?" x8 i. m
    数组指针
    % `2 u4 C% ~4 k4 u数组基本表达% I& {% \" }* ~" o$ B
    int a[10];  // 定义了类型是int, 元素个数是10的一个数组。
    % Q5 c, g% e; L2 l& K- y由于c++要支持一行定义一个类型的多个变量。 所以数组的[]时放在名称后面的。虽然我觉得
    / ~) \: l" d: Y6 D$ ~, n0 J8 U* z* k% ~. @% b! \
    int[10] a;3 M  W; p# X3 D" M5 {/ H; e
    这样的写法更符合类型 名称的思维, 但是如果类型都这么写的话, 没法兼容以下的写法:
    6 \  G% [% i9 M# |" A& }0 U4 ?8 r# X
    6 l3 Y& Y  V& P# {6 }int a = 0, *b = nullptr, c[20], **d = nullptr;! ]7 S) ?  S& K- ]3 B6 b" t
    c++标准规定如此,但我们可以通过每一行只定义一个变量的写法, 类型会更加清晰。9 N. ~  {2 z6 C0 Q; O+ n
    : c# ]$ X: E% @' ]
    int a = 0;. m! l5 V; K) `# [2 c* J$ u) O
    int* b = nullptr; // 指针int*
    6 Z4 |! O7 Q0 U3 o3 f0 ]int c[20];
    $ p) S$ o' y2 P$ F6 g4 X1 ~. `int** d = nullptr; // 指针的指针int**& m. B' A( r; z2 m: I
    数组的名称是什么类型
    ' ~/ f9 L, B, G1 T1 h6 O8 O$ Q数组元素类型的指针,可以直接指向数组。 并且数组跟指针一样,可以通过下标去访问元素。
    * \! G' d' k5 r+ e' y) ^9 K( o4 U, O6 f8 J7 f; Y
    int a[10];8 i7 U* {0 z5 ~5 O; J; s: y' J
    int* p = a; // 指向a数组的第一个元素; j/ I5 Z) ^7 y
    a[1] = 1;
    2 U4 O1 \4 \" I1 H* c/ zp[1] = 1; // 效果与a[1] = 1一样。/ j0 h3 \, ?; V; W
    数组可以当作T* const来使用, 但是又与T* const有些不同。sizeof()的结果不一样。
    % T+ y1 L" D: F% N: u& m  m0 x9 Q4 X& Y0 C
    int a[10];# Q# O5 Y( g3 Y
    int b[10];
    0 U/ z# m. ~$ b7 A) `' Bint* const p_a = a;
    2 L' n- H' D3 U, C9 n: E* ta[0] = 1; // 合法。 数组的元素可以修改。* Y" t* k% n% h* Q: D4 ?
    p_a[0] = 1; // 效果与a[0] = 1一样。* m/ a7 p8 W! j) ?7 z$ _9 z

    ' j( \' \1 O% ?+ X2 i; ga = b; // 报错! 数组本身的指向不能修改。
    & M  h/ w) {+ G0 ~9 J+ G5 B0 h* j: M1 y+ I7 o) {
    // 所以数组a可以当作int* const来使用
    * M. K6 k* L$ U- I" `8 [8 c8 jint *const& ref1 = a; //正确。
    + B$ E/ b/ W" l& f0 I( bint *& ref2 = a; // 报错!
    ! V$ q( _0 r: X" s" _3 ^4 _2 K  F( ]" K
    // 但是又跟int* const有些区别。: o% b* x# ?7 [) y3 {
    assert(sizeof(p_a) == 4); // 32bit程序。
    3 i$ N& F, b* r! [9 ^. Qassert(sizeof(a) == 4*10); // 32bit程序8 p. |( I$ t7 |7 V4 L
    & a6 R& l, a# f9 N6 Z. {) R
    数组跟元素指针的作用很相似,都可以通过下标去访问元素, 但调用sizeof()函数的结果不一样。元素指针的sizeof()返回值是4(32-bit应用)或者8(64-bit应用), 数组的sizeof()返回值是数组实际占用的空间。数组可以当作指向第一个元素地址的T* const来用其实就是我们常说的数组到指针的隐式转换。当数组作为函数参数传递后,会自动退化成T* const, 在被调用的函数内部调用sizeof()的返回值跟T* const指针大小一样。 数组传递作为函数参数后, 在被调用函数的内部与T* const是没有任何区别,只有在数组定义的可见范围内sizeof()才有获取数组占用空间大小的效果。
    % j/ v. {2 Z5 D0 |% W5 `: |$ n. M; ~  [/ F0 p! t
    以下3个函数翻译成汇编以后,汇编代码是一样的。
    8 f2 b1 G6 ~8 w; y: l
    ) n4 S9 w1 E& A% @3 O- s: _7 n7 g& Xvoid Func1(int* p_ary)
    3 M; r5 H( D+ t9 ?; P# L{0 d! o) u. w. A) j! F2 {
        assert(sizeof(p_ary) == 4); // 32-bit* `) `( h2 V7 v' o
        p_ary[1] = 1;
    5 @5 s8 V* M9 u4 _4 X9 v. }' V}
    8 u& d( X' k) s% e
    - N8 Q. Q8 F. {2 T) Fvoid Func2(int ary[])
      R6 E  ^% E. r{
    - ~, P7 F/ X1 w- Z    assert(sizeof(ary) == 4); // 32-bit
    6 ^& H5 W5 ~) f" @8 `0 e! r' T    ary[1] = 1;
    & I; j/ Z9 o+ ~3 B8 l}
    9 V( S: r# B1 u; G
    % p! e" Z" Q/ J4 S1 A) t" ovoid Func3(int ary[10])
    3 R; O& l9 D' f8 S' K, @, S: Q3 F{2 t  s& T1 R9 s0 s( D9 w. q* ^
        assert(sizeof(ary) == 4); // 32-bit: `: i+ ]( @* ~" S% \5 N) s& q
        ary[1] = 1;+ l5 L' W* S+ A& C* d
    }
    # V0 s4 v& {: x/ ]
    , O8 I7 A9 [  ^7 N. L: yint main(int argc, char** argv)
    1 j2 J; V, N5 @8 b" k+ F{: ]0 t3 j: j) d8 n
        int a[10];; W3 L9 q8 F2 l  I
        int b[20];, d* T2 j9 S9 M
        Func1(a);
    ! J2 V0 X3 O0 _4 y- r    Func2(a);* B  N) J0 D' {
        Func3(a);
    : t' @3 q5 [) _* J7 p    Func3(b); // 退化成int* const了, 即使数组长度不匹配也不会报错。
    9 g: L0 E6 k1 s& S$ C' s( F. e    return 0;
    0 I' p9 K  ?- h6 f/ n}( j- R. ?- r  l& z) R

    3 m" [' T7 J$ K: G& S$ |8 T$ u9 N+ C6 W- ?) y
    4 W, V1 G' v6 B# v9 g5 ?9 o
    多维数组
    / a/ {! B1 e' v& e' w一个3行,4列的数组, 结构如下:
    4 e0 W+ K  j5 z$ C' t
    . v& K( R0 ^) k; H3 U4 Eint a[3][4];8 j4 W) t5 ]! ~) W# b
    column 0        column 1        column 2        column 3" \* W8 `1 Y' {# j6 Y
    row 0        a[0][0]        a[0][1]        a[0][2]        a[0][3]
    $ Z8 X: t) L# w* g& ?row 1        a[1][0]        a[1][1]        a[1][2]        a[1][3]- X% d8 W  w/ A& ?0 C& E
    row 2        a[2][0]        a[2][1]        a[2][2]        a[2][3]
    # Q0 |" W3 r, b5 t: d4 M数组初始化+ h0 k; U, [/ ^

    / |, j: T8 w$ D5 K" x+ F' C2 V& gint a[3][4] = {
    5 P+ n1 }2 p0 y/ s* H4 ]. P4 X    {0, 1, 2, 3},
    4 ~* y1 {$ g1 L/ G    {4, 5, 6, 7},* G8 C$ l( I. }$ {2 s% s2 }
        {8, 9, 10, 11}
    # u# z( \; t. @# t};; b7 B" A; ?6 ], i0 ]
    实际上多维数组和1维数组在开启速度优化后,翻译成汇编代码是一样的。! f6 \# n1 T; b) }, T+ J
    " L( _1 F  E  ^$ w+ g, C
    void Print(int* p_ary);
    7 k) K0 g3 _6 C" m
    ! h+ B$ u. y/ A7 y9 d0 ^void Test1()1 n4 m6 w) W5 @
    {: R8 _2 S8 n( R* ~/ _$ I
        int a[10];
    4 J$ ?$ q) v2 ?% {2 |7 y    a[3] = 3;
    ' {. n. u9 I5 F+ i, b    a[7] = 7;
    * I$ w/ I3 g6 f0 f" o# u. n7 R7 G    Print(&a[0]);1 W7 o$ @9 W! E3 M0 ~7 x  S
    }3 L2 ]1 S. X7 T; k2 Y

    0 s7 \) f5 Y8 p: a( }/ Wvoid Test2()
    5 c) u, w% J  g. r3 P6 t{
    # C! L0 p5 C1 ^, D5 I+ p  Y% [% k. m    int a[2][5];
    * J+ D+ V* Y! h3 M2 N    a[0][3] = 3;2 C* y& r- Q: ]1 O
        a[1][2] = 7;# Z, a( ?9 \1 N  Z
        Print(&a[0][0]);
    / r  |, n8 G2 c5 q}) T; o) S& e5 i" a/ \
    ) R6 v1 p, B/ m
    8 P2 L- T, A' `, R5 H+ n, p

    & P* d  o1 j1 n8 C  E很自然地,多维数组也支持用1维数组的方式去初始化。
    8 T+ A* O3 x' Z7 `0 I& n% H( j
    . c  M. O, a- l' Nint a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
    5 T, V$ {1 \5 u3 o2 q+ [* ^既然多维数组与1维数组没什么区别, 为什么还需要多维数组?
    % y8 @, C. ^; y* R$ s9 Y2 Q; e: M( y4 ^
    假设有一幅RGB图像720*576个像素,每个像素有RGB三个通道,每个通道的值是8bit大小。给出图像的首地址p_rgb_image, 我们要取第40行,第50个像素的R,G,B值。代码如下:
    + m$ H: C7 P; p8 c! s' Q6 p* e% e. Z) J  y9 d6 g, A1 ]1 J$ Z
    unsigned char* p_rgb_image;
    1 I1 c" t4 J9 _/ [6 Uunsigned char r = p_rgb_image[40*720*3 + 50 + 0];3 V/ [9 ?% K$ v' U
    unsigned char g = p_rgb_image[40*720*3 + 50 + 1];
    6 Z2 G; L9 b/ N* p( ~# _0 g/ V# T6 Z. Junsigned char b = p_rgb_image[40*720*3 + 50 + 2];
    ) v  J" K. S# r" Y* l: u/ a2 Q类似这样的场景, 采用多维数组的写法, 有点类似以索引为参数,可读性更高。相当于程序员和编译器打了一个配合。
    % `! Y% ^+ _/ l. H& b. @5 l
    7 e( ?9 r! E1 c3 l; S/ H( f/ e1 D1 yenum0 D9 d. V* o+ k" F6 j/ R  t0 d
    {+ g( P9 U6 B$ d1 U
    Red = 0,0 e' f7 g: n5 B( X
    Green = 1,
    " S, Z2 ]/ f6 p9 m! w8 r Blue = 2
    , C  @; ?6 {  B};. ?: Q2 R% f2 k8 ?/ f7 Y
    unsigned char rgb_image[576][720][3];, [: m. D7 l( F* ^
    int row = 40;* _) @1 d1 l& p' I0 A+ O
    int col = 50;
    & C2 J5 l% u  M& L; m: \unsigned char r = rgb_image[row][col][Red];
    ! D5 s9 ?6 g1 y0 kunsigned char g = rgb_image[row][col][Green];
    % B" J. s+ s2 Y2 M% `' {$ munsigned char b = rgb_image[row][col][Blue];) _3 Q7 E  [9 W2 N, M
    数组指针以及与指针数组的区别
    + B+ _2 S  b7 p/ q/ w数组指针,是一个指针, 指向的对象是数组。 数组指针的赋值,要求数组的长度匹配,否则会报错。当指向1维数组时, 需用用*取得数组对象的引用,再用下标来访问数组元素。
    1 K; i5 T8 N- m* ~指针数组,是一个数组, 数组保存的元素的类型是指针。
    + }3 m9 h* V: d) s: s% e* C7 r8 E0 w3 G数组指针的定义- p9 H5 G+ D9 w
    数组指针定义先定义一个数组。
    9 i& i, U2 q& {( k' k. y/ fint a[10];& Z& b' i4 |  R% G( Z7 R
    然后对数组里的名称用括号括起来后再在变量名称前面加个*号
    " P0 [5 G- p6 B- Zint (*a)[10];
    7 J9 ^: p. s0 s( `. v6 C后面你会发现函数指针定义类似。7 N4 T: j4 d- f: f& z
    // 各类定义对比
    % D# u, t# I6 P7 }' {0 Pint a, *b, **c, d[10], e[10][20], *f[10], (*g)[10], *(*h)[10];, x0 `  _$ D" {8 m# n# |
    8 |3 P$ j, ?9 h" K$ S
    int *f[10]; // 指针数组, f是包含10个元素的数组, 数组里每一个元素的类型都是int*6 D1 p) K7 H, B$ u9 d3 s- |& a
    int *(f2[10]); // 指针数组。另外一种定义方式。
    2 N: y. g' [. v  pint(*f3[10]); // 指针数组。另外一种定义方式。; z; V3 k6 o" e9 K0 _% `
    int(f4)[10]; // int数组
    - G9 d; X4 S% d4 Yint(*g)[10]; // 数组指针, g是一个指针, 这个指针可以指向类型是int,元素个数是10的数组! v; _8 j6 E9 ?  ?3 w; L' @2 I
    int* (*h)[10]; // 数组指针, h是一个指针, 这个指针可以指向类型是int*,元素个数是10的指针数组4 t1 [& b( `, o; t( G
    # d* T8 q- V  Y
    int d[10];
    ) X: r' W# d! i9 J! ]7 Rg = &d;2 R$ U& j- |& X2 a2 I1 X" Q. I

    : R! R2 I3 t9 ^  t! Wint* e[10];& s# @2 d  t6 d1 o3 {+ w! f! N# I9 ^
    h = &e;
    1 M6 V: p6 U) k& q2 s2 _1 ^5 X4 a- q数组指针的使用- Y* c6 t/ J7 z5 |
    数组指针一般先通过*号取得指针指向的数组对象, 然后再用下标操作访问元素。: R- t7 H& s( R9 P. w2 N9 P

    ( J+ z$ b9 j" pint a[10];& T# N3 v. h+ K
    int(*p_ary)[10] = &a; // p_ary是一个指针, 指向"int (*)[10]"类型的数组
    6 V4 A; a; ?( [/ r: A! e7 hfor (int i = 0; i < 10; i++) {
    % o- @/ `/ B4 w7 h* ~7 G+ r/ t( O // p_ary是一个指向数组的指针, 需要先通过间接寻址运算符*(indirection operator)取得数组对象! D6 b: ^, y6 M: A+ a% @
    // 再通过下标操作访问元素。
    . N0 U- }/ ?1 V% s (*p_ary) = i;
    ( Q# z. [$ m3 R! P2 o; I! F}* j. m5 B/ Y: j/ g- w( E3 J! O
    8 P# G4 h0 q, F( q
    int b[10];
    1 K& Z3 v( s, b( V0 zint c[20];
    5 V* O+ k5 Q- E& x7 Ep_ary = &b; // 合法/ r3 |( S: X/ ?
    p_ary = &c; // 报错! 不能将 "int (*)[20]" 类型的值分配到 "int (*)[10]" 类型的实体* ]  h2 K6 H  `( M: Y$ M1 f& }
    数组指针指向多维数组的子数组
    ; c  l& u3 A% z4 K  wint a[10];9 n- v. T# N* Z" F6 Q
    int b[4][10];# y# c, Z& J% V0 f9 D) Q% \& p- E
    int(*p_ary)[10] = &a;; T$ K. _. u7 s# j, f! M
    for (int i = 0; i < 10; i++) {/ `/ x& h/ Q/ H( k: s3 u- M- O2 m
    (*p_ary) = 1;
    0 p" G( S1 s' G2 v0 c% G( N( F+ I}( f$ }( f) j$ R1 {

    * I% m6 m; W8 e% Kp_ary = &b[2]; // 多维数组,可以看作数组的数组,+ q5 h; ^  P9 z' c" M; W
    // b[2][0] ~ b[2][9]的值都被改成2了) ^9 A* O; W6 s9 H8 Q5 D7 t
    for (int i = 0; i < 10; i++) {' F  D2 E5 V' x- n% `
    (*p_ary) = 2;; Q( X  Q: f1 V' Y+ s1 I
    }) y( i( U; a3 k/ w% {
    多维数组指针5 P( J* x- @6 l3 @% G5 T
    多维数组指针,是一种指针,指向的对象是个多维数组,支持多个下标操作。4 U7 o* M6 n. m* R9 R% e4 ^
      \5 n# z% Q+ m; q! ^- T' H" p
    int a[2][5][10];
    1 k3 ]  j1 T# N' V* X1 i2 t. `  vint(*p_ary1)[10] = &a[1][2]; // 1维数组指针; ?5 |3 a$ P8 ]8 L
    int(*p_ary2)[5][10] = &a[1]; // 2维数组指针+ C7 T  U; R% c6 }8 i1 a6 h. [) K
    for (int row = 0; row < 5; row++) {
    3 a3 a, ^: t1 d0 n5 Q    for (int col = 0; col < 10; col++) {3 Q3 \0 A0 ~1 m) G: C8 U
            (*p_ary2)[row][col] = row * col;
    8 p/ P: J3 Z5 B  H" Z$ p    }( K# \! P6 @* [5 R+ C# V
    }" o6 n& Y" o/ F9 ~6 Q& \
    数组指针和指针数组对比实例8 g6 n: @! _3 c5 ~' I3 U) l8 @1 k: s
    数组指针还是记住两步法即可$ H3 w/ S% M; S# J4 q" Z3 ?
    $ k/ }* [, ?* V7 @$ |- g
    定义一个数组9 f" \4 q8 O& s  j
    括号包围1中定义的名称,再在名称前加个*号。& L8 v! _8 R( g
    int a[10];. u" }* v: Q' \" t6 P
    int(*ary_pointer1)[10] = &a; // 数组指针( j! R* C  D8 x4 V/ F2 K7 @
    int* pointer_ary1[10]; // 指针数组。元素类型是int*1 J' Z' C" g8 [0 N- O
    int *(ponter_ary2[10]); // 指针数组。另外一种定义方式。
    4 w0 O0 q$ e) P6 _, {+ T; dint (*ponter_ary3[10]); // 指针数组。另外一种定义方式。
    8 s" o4 _3 E& hint c, *d, (*ary_pointer2)[10], *pointer_ary3[10]; // 排列定义比较。
    1 A# l& h9 J; D1 B5 Y; s3 r. M2 F/ l9 u7 O) q; l  ?6 U0 e/ x2 \* P: F
    // 指针数组可以把每个元素指向数组对应位置的地址。
    ' d3 N: J& Q) Q4 X2 _5 F4 R/ T// 这样遍历指针数组, 可以达到遍历数组元素的效果,但是注意每个元素都是指针,
    5 s! x& u0 j# P* t// 需要访问原数组的值的话, 需要对指针用*间接寻址运算符。4 b8 v  b. {: @6 ^
    int* pointer_ary[10];
    4 \& }% w( m. f/ ?4 c4 K, ]+ Lfor (int i = 0; i < 10; i++) {
    5 p8 `' ^5 Q: z    pointer_ary = &a;
    * M; n9 z  K/ d3 b}( [, d5 d$ x  h* ]; D& o, W
    // 类似遍历原数组效果。
    2 z0 {8 h3 t4 v2 V/ Q2 rfor (int i = 0; i < 10; i++) {. J  y) D1 k$ |! ]/ L8 H
        *pointer_ary = i; // 修改原数组。1 |; ?  T/ D% |( M4 L7 v5 `$ v
    }! m# C& h; ]" F& V& G8 h

    ( L; D2 B& f" C$ x函数指针# a; p! ^. A5 C/ i
    取得函数地址
    ( X  {4 c  p" y" ]- V$ B; }2 q, S/ m3 w函数的名称作为参数被传递时,会隐式转换成函数指针, 和在函数名称前加取地址符&等价。建议带上更加统一和清晰。/ \8 ^6 O& }0 s; |4 ~9 ~

    3 ^1 {7 p# v  [8 {1 [) X- Jvoid f(int);1 _! E% l% g' T- P
    int main()
    # x1 P- Q3 P$ J1 v/ A, t! Y{( `* H; H1 a; B$ E5 h
        void (*p1)(int) = &f;5 a' X) E/ z# ]9 L* l: q& ^
        void (*p2)(int) = f; // same as &f
    # l% p  C, T9 ]    return 0;
    ) \, w4 U/ c& }  X}* Z* K" N% ^+ J" M5 J, A
    翻译成汇编代码, p1和p2的赋值是一样的。$ n" h. R: @* Z9 t- @0 `

    2 Y0 v* ]' e6 y7 }1 }7 Z4 b! N: }1 y1 L+ W! {; ^) B' z
    2 Q: Y' Z% R; v. C2 N* V  d! ^* X7 [
    函数指针的声明
    ( A. a) M$ }% V单个函数指针变量定义步骤
    ; Z& v9 v8 v! m0 H$ ?定义一个函数。void fun1(int a, int b); int fun2(double a);
    2 ?+ T" {: X$ v/ |5 I0 D5 a2 H用括号把函数名称包围起来,然后在名称前面加*号。void (*fun1)(int a, int b); int (*fun2)(double a);
    1 E# h) ]! d8 n$ b9 Z2 l8 k如果要定义函数指针数组,在定义单个函数指针的基础上,在名称后面加上[数组长度]void (*fun1[2])(int a, int b); int (*fun2[10])(double a);
    ; j/ E1 ^: j! ptypedef定义函数指针! C# }1 w! d* X& q! v$ x
    可读性高比单个定义要高,特别是声明多个同类型的函数指针,或者函数指针数组。
    7 V% b! t) S; y* `
    0 y9 `4 }9 m8 R( F' ~  Atypedef定义函数指针的语法* ^  h9 L+ v/ R9 h5 S( X7 k
    typedef有两种做法, 一种就是定义一种函数对象,另外一种就是定义函数指针。用法稍稍不同,效果是一样。其中函数对象不支持赋值, 但是支持引用。+ @% g5 i1 `' [" A  Y* u3 F3 p

    2 C- c3 H' A, T  F9 D) o9 t! rtypedef int FuncObject(int a, int b); // FuncObject类型是函数对象5 P- e7 F. T, ~1 e" q: ~  n: l/ [; W
    typedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针
    4 @+ N' h% ~7 ]" b9 D$ MFuncObject* f1 = &Add;+ r" R- h$ y0 W! I
    FuncPointer f2;4 I2 N% h$ }2 N
    f2 = f1; // f1, f2类型一样, 都是形式为int(int, int)的函数的指针。
    4 W/ g& Y+ r7 @* y+ r- IFuncObject f3 = Add; // 报错! 函数对象不支持拷贝
    8 }3 E; L9 B, |* [1 n# CFuncObject f4 = &Add; // 报错!&Add是函数指针,与函数对象类型不匹配6 _6 F1 V' l- ?. ]3 ]1 j
    FuncObject& f5 = Add; // 正确* j1 S* z, t8 ?, i% J# W0 {# P
    int ret = f5(2, 3); // 正确  n3 F- S4 |* I! P
    FuncObject& f6 = &Add; // 报错!&Add是函数指针,与函数对象引用类型不匹配- f( \0 u/ f* p/ f6 h/ Q
    如何记住typedef定义函数指针的步骤: o& _1 R6 O! M$ u
    像定义一个函数指针那样, 指定一个名称。int (*CalFun)(int a, int b);
    3 S. J& a, m6 V& Y在这个函数指针变量声明前面加上typedef。typedef int (*CalFun)(int a, int b);
    * w! [) E2 t* s+ b/ G0 w完整例子
    . U6 v/ T% l4 G( ^3 k9 _typedef int(*CalFun)(int a, int b);
    1 m- e; S2 C! O. o, p. l( s. A( Q" O5 ^
    int Add(int a, int b)" a# S( F* O. n9 R
    {' [" u' Y8 _( A% T- f
        return (a + b);! P! |: J9 r) m, f
    }* k/ j7 ^( g) j: ?  `

    , N% U9 u& R" n& ~( h4 |int Sub(int a, int b); o$ Y0 K; D4 C0 t! c: R. y! C" K- @
    {# `3 b0 Y6 \- U! n5 E2 S- C
        return (a - b);) }& c/ c8 Y3 S9 H+ q8 C+ l
    }) \( {0 r8 A4 u+ j

    . c4 Z$ y! L/ k: I7 G' g! R7 r) kint main(int argc, char** argv)- L. h' k5 \. I1 W
    {* z5 h- m" U7 a5 \- |  Z' X
        CalFun f1 = Add;" l& e! z5 _" k4 m
        CalFun f2 = Sub;* }( K9 W9 ], }% T' r) B0 x2 i$ H
        int a = f1(2, 3);. U5 p6 _9 \0 L6 w
        int b = f2(10, 5);
    / d! r1 W" E& H* _' f- D
    5 G! J  r, u1 W# B/ G( \+ Z1 q    // typedef定义的函数指针数组。0 P% f/ F5 i' [) j- p
        CalFun f_ary[2];. n# G5 N! {; `' g% _( N9 B: j
        f_ary[0] = Add;
    6 b4 a2 m* @5 \& {. `$ c' {. J    f_ary[1] = Sub;) _6 Z+ o2 V5 x! b9 C1 T
    , d- Q! j6 L6 A& H1 a4 K
        // 单个定义的函数指针数组。
    / y( O$ Q, y7 r4 e    int(*f_ary2[2])(int a, int b);  f2 u5 a1 @1 u, f
        f_ary2[0] = Add;9 O4 O  Q2 Z( z9 I: \) n
        f_ary2[1] = Sub;5 C0 w7 h: c, }6 k  H

    # i- V. s+ U2 V! {5 s. T    return 0;, X# H, f1 i" W& N; X5 o* d
    }4 d, H' s' m9 w1 d" c7 v- E5 @

    ; I, {& [, b' z+ l. Gusing别名定义函数指针  u( f5 g! c$ b- ~! s' }) E% G
    c++11以后的类型别名定义--using也可以用于定义函数指针, typedef的好处它都有,个人感觉比typedef更直观。using类型别名同样分函数对象和函数指针两种方式。
    3 R0 F" b0 V1 T' U& G! i; E. u% |+ F' l/ X. ]. ]
    typedef int FuncObject(int a, int b); // FuncObject类型是函数对象
    9 [: y9 P( x* Y) R: ~using FuncObject = int(int a, int b);: y7 d; ]. J' U! q5 g" X
    typedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针+ F  ~1 y6 _5 s7 W; D" J
    using FuncPointer = int(*)(int a, int b);
    " ^* [6 f9 f5 F( G  k* A函数指针的调用
    0 j6 F) F8 @) |: x函数指针和函数对象都可以直接后加括号调用+ I1 D# c( [/ R9 N  d* m% f( e& T% k
    int f();
    : k* _, A* N( rint (*p)() = f;  // pointer p is pointing to f' e: g' G7 w% V* \5 t0 O% j8 k& Y
    int (&r)() = *p; // the lvalue that identifies f is bound to a reference
    ' K2 N5 }( _- z4 G6 N: fr();             // function f invoked through lvalue reference$ U; L7 b$ S9 Y; f
    (*p)();          // function f invoked through the function lvalue
    9 Q' x" I3 ~4 a' W/ i9 l7 sp();             // function f invoked directly through the pointer" t% n$ j2 d% \: d
    如果函数有重载, 函数指针会指向匹配的那个版本。! {. O3 ]3 g. d1 L& G9 K
    template<typename T>  H" v9 h- @6 ]. v8 F- E  [
    T f(T n) { return n; }
    # `% h$ b3 M& T& ]9 S& V5 f! h) h  \2 u3 A) H
    double f(double n) { return n; }
    # X5 {& B* K( S7 G. Q
    1 s; Y2 W; d9 R6 [' d: Q$ V/ B* Jint main(), I3 E" _8 \1 c
    {
    $ l! |8 S1 b/ D    int (*p)(int) = f; // instantiates and selects f<int>; ^( E/ R7 ?; o& q& W. y: D% ^
    }
    " |) q; p2 v" Q# W' N( B成员函数指针7 Y8 A4 y) g" `: \4 Y6 }
    静态成员函数,除了增加了访问控制以外,跟普通的函数指针没什么区别,所以普通函数指针可以直接指向类的静态成员函数。但非静态的成员函数与普通函数指针不太一样,声明时需要指定函数归属的类名,并且调用需要指定对象实例。9 o: P& F- ^3 S, I7 t1 ?
    5 W- l5 f( e' U5 P+ m7 U& E
    成员函数指针定义。
    & R1 q7 J7 D% s; {5 |4 i像定义类成员函数实现那样写, 并任意指定名称,这里作func。void ClassName::func(int);9 s! y, r9 k+ l, A" M& o+ x
    括号把类名、范围解析运算符::、名称包围起来。void (ClassName::func)(int);
    + p: n$ W& _* T; y  ]/ ^7 x在名称的前面加个*号void (ClassName::*func)(int);3 ]3 q0 x1 V! X' N; i7 y! [! E# b
    成员函数也支持typedef和using的定义方式。typedef void(C::* MemberFunc)(int); using MemberFunc = void(C::*)(int);, U/ g. o4 S' x$ g- s! K  d0 e$ \
    成员函数指针如何调用。
    ' Q) @3 b# a6 A( i" S假设成员函数指针名字为func* @( s' t- Q# t3 {* E  a

    + I) _, W& x: k8 ~1 @void (ClassName::*func)(int);! U# L; |- i9 x% Z1 p6 T; D9 k
    对象式调用。
    3 T5 \# T5 N/ \& H' wClassName c; // 被调用的对象
    6 w! D: H, L, W4 D成员函数指针名字当作正常函数那样写。# X1 o: K$ X' Z. U7 w0 w
    c.func(3);3 k4 r# U0 z" ~$ u3 ^  X# Z2 ~
    成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。
      I* T+ y% N& a. \5 S! w; oc.*func(3);
    9 a) g$ j5 C' u" [0 {最后用括号把调用对象、成员访问运算符.、间接寻址运算符*、和成员函数指针的名称包围起来。! r8 D! S8 S# u  X9 b' c/ k: \
    (c.*func)(3);
    . v! k( d' w" `- b( @# L4 _, K" G! |为何要加上括号? 根据c++的优先级标准,取成员运算符. > 函数调用() > 间接引用符*。 *号优先级比函数调用要低, 成员函数指针还没取得对象就被调用了,自然报错。 另外, P1 I; Y3 m+ i: P' y
    (c.(*func))(3);  N4 u$ ^; ^8 Y$ X- M& i( ]# f
    这样的写法也不行。 .*和->*是整体作为一个运算符的,中间不能用括号隔开。
    4 X) S* G5 ?) |! s9 R: a( J指针式调用: n8 y  J" Y' z4 P3 Z* P
    ClassName* p; // 被调用的对象的指针
    $ E$ {& O# ]/ f" U: |- \) `0 G成员函数指针名字当作正常函数那样写。) u, T, M; I2 v( S7 F- C  f9 f
    p->func(3);
    7 N. y( e) W3 I2 ~2 j) D成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。1 L: g$ J/ f4 C; ]1 j- h; l
    p->*func(3);1 s- L) f: H$ q/ d
    最后用括号把调用对象、成员访问运算符->、间接寻址运算符*、和成员函数指针的名称包围起来。
    8 W8 _% b7 z6 }2 E' q(p->*func)(3);1 r+ b; y# S. ~9 I# q' E1 i3 _0 ~6 x
    函数指针使用完整例子
    * I% ?8 Q/ t& G# I) V+ u' Pstruct Cal
    " L  b' A% M- d" ~: e7 d{
    0 g" S- p! I7 U: R6 Z/ k4 e0 C* m3 k    int add(int a, int b);
    3 p$ H! {+ z& u5 c% t9 d    int sub(int a, int b);4 z/ X1 K  z7 s
    };
    , V9 n1 Y' q: i) [: Q- {' |& A1 d% \0 c' r6 v
    int main()( I2 n4 T" c$ C1 R' ~% K4 Q
    {
    + _* H$ Y) y* Q# Z2 D" W0 ]    int (Cal::*fun)(int, int) = &Cal::add;
    ( M# J# Q6 A! P- h# @7 w# ]    fun = &Cal::sub;
    9 ?8 k  b- R& b4 v( v+ ]" |/ f4 \. g. U0 L+ a. C, c! ^( [4 h
        Cal* p_cal = new Cal();" U# X) A! B- G! f& d& k0 o4 v- x
        int r1 = (p_cal->*fun)(2, 3);* y* t9 H  r" _& z7 ]
        delete p_cal;2 |* d  T, \- l  u9 _5 |
    / `5 u1 G6 B% p' ?) \1 Q) s
        Cal local_cal;
    : C! S7 \# q/ d; E9 p% T. B    int r2 = (local_cal.*fun)(8, 6);2 F' Y2 T; k& M' \0 P$ O% H, j! O
    }% G$ k: O# W0 U  v) L

    0 d6 ~/ _: ~2 a9 S. K成员变量指针4 Y1 D/ n7 ]1 ^  g. i
    成员变量指针比成员函数指针还要简单些,没有函数调用, 无需考虑函数调用和间接引用符*的优先级问题。/ b7 M, {& c3 Y% g9 h6 F+ R
    ) ^" \1 l" t+ L
    成员变量指针的定义
    8 J( u5 t+ I: H6 h6 F假如以下结构体C。
    ' D: _, s& b; E2 c6 o" c# h7 z/ Q& a+ `  i) \  L, L1 X" s
    struct C 7 b+ ]# U- s- Z' X
    { 9 _& M2 O2 O4 I. I) z  s# [* v
        int m; 0 L& f& {$ u. ~6 q3 [8 E* a# `3 p
    };+ t7 |. B7 b1 A
    单个成员变量指针定义 / N6 L6 H- g3 O7 e# V4 N
    假设名称为p, 类似静态成员变量定义那样声明
    2 q1 ?9 R6 s' L) ?- N; N) t9 Xint C::p;
    9 ]4 c+ X8 a! b# J在名称前面加上指针标识号* 9 u' ?2 `2 R, I' s7 g/ R
    int C::*p;
    3 B( C9 `$ F) ?3 \typedef或using方式定义
    4 q7 f; N6 X+ ^) Xtypedef int C::*MemberPointer;1 t2 ~* T5 X4 G9 D, o, v7 g! [
    using MemberPointer = int C::*;
    2 c9 Y0 K( r# S6 ?& N4 X: k成员变量指针的使用。7 Q! b& ]4 R, m# M+ O' \2 q
    类似成员函数指针那样,直接使用指向成员的指针运算符:.* 和->*即可。
    ! A5 R4 _3 [" s3 M2 O2 U- q2 _成员变量指针, 能让我们实现一些遍历成员的动态功能。 例如把一个类/结构体的多个同类型的成员变量放进一个容器里,然后遍历访问这些成员变量。
    7 W; t8 o3 w' Y5 n/ c' }( {* E) b2 t' [. D' S) k
    完整例子
    . ^0 R# O  W& j+ Kstruct C { int m; };$ T: }) R+ w7 k; z/ A
    int main()  o0 C) _) o# u! J, p) U& x
    {# C% R1 i+ u* f* j3 D
        int C::* p = &C::m;          // pointer to data member m of class C
    * {0 o. C7 ?+ A2 F2 V0 R    C c = {7};' K- K, ]% S" h7 X- _& }
        std::cout << c.*p << '\n';   // prints 79 [3 _, O5 l4 c
        C* cp = &c;
    4 w# r2 ]" F8 V) F% M; L$ B' `    cp->m = 10;# O! \" s/ f9 B
        std::cout << cp->*p << '\n'; // prints 10
    # ?0 l, {) T/ l+ `$ W$ s
    & [$ X9 ?+ l: r3 r7 M————————————————/ }, W9 p1 p* e* a8 i
    版权声明:本文为CSDN博主「南风fahaxiki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。( p6 o5 e5 M' R
    原文链接:https://blog.csdn.net/m0_64407685/article/details/126788115
    * Q( ~3 ~2 `9 F4 K% _# W& m2 m( H8 [. b9 R; d. @8 t2 M5 `  b. ]
    5 n- Z) Z0 S% }! T) s9 @$ s
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-4-12 15:40 , Processed in 0.437008 second(s), 51 queries .

    回顶部