QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2454|回复: 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++数组指针、函数指针、成员函数指针
    , a- W- H' p/ o' b$ `! M+ HC++数组指针、函数指针、成员函数指针
    / k( T5 ?& l3 G6 U: A6 X! Y! r( p- E+ c7 m# t3 G# I* b

    : K2 c4 g8 C0 \' X, ]; [操作符名称9 l. V9 K" M' R
    & 取地址符(Address-Of operator)
    % L, |- K. h% }) }, T5 j! w: V* 间接寻址运算符(Indirection operator)% M9 ?2 m: x5 |( r' g6 F
    .和-> 成员访问运算符(Member-Access operators),用于取对象的成员。
    " M$ P0 u0 t* @  \.*和->* 指向成员的指针运算符(Pointer-To-Member operators), 用于成员函数指针和成员变量指针的取对象。
    ' l- z0 s5 g' C( }5 \$ R  ~() 函数调用运算符(Function-Call operator)2 ~. R0 A$ u, u2 e5 s: t3 I$ p
    :: 范围解析运算符(Scope-Resolution operator)
    " s3 p# m# m6 v( }- Z4 u+ S! x如何定义一个指针变量
    ) Z% v0 b# ?* g! ]假设类型T, 变量名称name, 指针的定义如下:- |" ^4 `: ?; C6 I* G

    ( q; n% Z* @' t# v! n9 b' H- jT* name;
    % L1 W4 L$ F4 _9 C' _标识变量名字name, 它是T类型的指针。例如
    4 Z3 j& j' c5 e8 v# n+ |5 q) R/ c$ o4 [& @( [
    int n = 0;" ]$ P$ d  N, v, ^8 ~" s
    int* p_n = &n;
    " {6 m$ F' \+ G  S$ fp_n是int指针类型, 指向某个int型的对象。
    3 f4 ^$ f( R5 L3 C' c- `* a( ]2 Y+ U7 e) L
    指针变量的修饰' x7 x6 U' C+ U3 [% }$ I. v
    指针实际上也是一种变量类型, 只是它保存的内容有些特别, 是指定类型的地址值,通过间接寻址运算符(indirection operator)*, 可以访问到指针指向地址上的指定类型。/ t& j$ A/ B- B; E/ y
    0 X& ]; y* A; F8 c/ p$ s; [
    指针也可以用const, volatile修饰。 const int或int const均表示一个变量类型是int, 且该变量不能修改。以下两种写法都可以:% {* |" i0 @- [( ]% ~( w8 a
    $ x. z) I  N9 d: X- N8 x# l/ R' ^
    const int a = 1;
    / @& |8 J- r3 Sint const b = 2;
    / l2 n+ q& f0 c6 B# E0 ]既然指针是也一种变量类型,同样支持被const修饰, 表示指针的值/指针的指向不允许修改, 指针所指向的那个变量是否允许修改, 那是另外修饰。写法如下:' p: t3 K; S! l  u& U; H

    1 m9 E+ @+ K5 z% R) R0 ?% dint a = 1;( R  G! K0 Y# l, A) i' H% G  c
    int b = 2;
    / k# R; R  q+ p1 r6 eint* const cp_a = &a; // 指针的修饰词,放在*号后面。- e  }9 {( e( C% ^
    *cp_a = 10; // 指针指向的值可以修改7 d+ {8 [( g' m& s
    cp_a = &b; // 指针不能被修改,报错!
    9 G( s* z: F- _总结带修饰的指针的格式:& d* ^7 H5 n& P0 w4 w8 w- @
    只要记住修饰词总是放在被修饰的内容后面。9 M  t2 K  R& i- i/ p- ~( ]

    5 x8 Y; q% k& C" Q; d4 g7 F: ]cv表示const / volatile修饰词。指针定义形式如下:
    ( n$ J0 b) d1 Z- G* b2 K! S7 [- I% `: x1 h8 k1 v' W' ?7 F
    T [cv for T] * [cv for pointer] name
    ; h4 U, X7 m8 r8 O注意对T的修饰放在T的前面也是合法的写法。6 D2 d1 e! _. ^4 N/ K/ d
    5 J& D7 T# X1 M7 m. v, ~7 @
    const int const c = 2;
    , J" z# ^  ^$ q: |7 z" C: a/ n2 c; r在mscv编译器下也不会报错。7 T/ Q! W  r2 Z" t5 ~0 p

    $ X/ F& n! \6 W; U' b5 b- c完整的格式:1 {; K8 T2 b+ ?
    [cv for T] T [cv for T] * [cv for pointer] name5 i; @6 Z3 z) G6 d7 O
    / s' {) j) H. o4 y& x" j
    Syntax        meaning* R2 z- F- a" ?* k' S/ o1 I
    const T*       
    9 d- A5 |( Y; V. A1 Rpointer to constant object
    % Z7 Q) b! b$ T, j. K, u
    5 w6 q4 {% J- P, j0 J" u4 \3 \T const*        pointer to constant object- l& Q( h* o# r1 v3 }& h8 ?( j
    T* const        constant pointer to object
      }. j8 H- ^" _+ I) fconst T* const        constant pointer to constant object) Y2 O/ H3 S+ m: U- }
    T const* const        constant pointer to constant object
    2 z# o" H+ H& d上面格式中T还可以是一种指针, 指针的指针仍然是按照修饰词总是修饰前面的标识(T或者*)来确定修饰的意图。
    2 r4 d9 q. I8 {$ m9 h# ~0 U! q, \: Q& P
    int a = 1;
    & b- I( d' {+ j4 W" @' a6 Zint b = 2;
    ! P4 ]) A+ Y( u; T/ _
    ' S/ K  Q# ~4 e. N& \7 \8 x- K  Qint* p_a = &a;9 U/ O$ l. q+ f+ W
    *p_a = 10; // 合法3 [2 O/ f! a& B: ]6 {( ^4 l" H. H
    p_a = &b; //合法' d! B) o2 L9 V0 _

    1 O8 X! I7 Z9 q2 E3 x% X4 }const int* cp_a = &a; // const修饰int类型, 并非修饰指针
    6 x/ \) W/ K0 [: D$ Y*cp_a = 11; //报错! const int类型不能修改
    1 H/ |: b3 |% {& c1 ~, m3 ~; D# kcp_a = &b; // 合法, 指针没有const修饰,指针可以修改。7 g2 g$ M7 Z5 R) ], {& Q

    0 i. u2 R1 j. pint* const pc_a = &a; // const修饰指针。类型没有const修饰$ K  A6 {2 F. n7 O( m0 c- Y3 b
    *pc_a = 12; // 合法, 因为类型没有const修饰,可以修改。
    7 A) e2 |+ Y, p2 p3 g4 W$ k% k" _! D1 Qpc_a = &b; //报错! 指针被const修饰, 不能修改指针。6 K3 M# x8 ?  ]0 ]" D

    % A: V5 g8 c' S: o# [int const* const cpc_a = &a; // int类型被它后面的const修饰, 指针符号*后面也有const修饰
    7 D/ F8 Z8 p1 b. V  |( q*cpc_a = 13; // 报错! 类型被const修饰,不能修改。: n8 U" ?- ~  Y
    cpc_a = &b; // 报错! 指针被const修饰,不能修改。- o" V' }: V0 U. [8 k8 H, g
    0 U) O' l8 j7 X9 j
    更复杂的指针的指针  ]7 s4 k' G5 m1 p4 U4 {
    % x0 {8 U" ]' M; s4 X, a, E
    int a = 1;
    5 j) h5 E2 }5 J+ Z9 Pint b = 2;/ V( D, A5 W+ g7 J" F
    int* p1 = &a;
    / |9 p! f! u; u# k1 ?% eint* p2 = &b;' V$ L% e) Y9 U- R# L4 R/ w! N
    const int* ct_p1 = &a; // ct for const type
    ! Z) e* m5 ~& w( y# R- Yconst int* ct_p2 = &b; // ct for const type1 T9 I2 a! G' y9 j
    7 }! q1 t/ ]3 b- ^6 x2 ?
    // int * * pp1; 指向(int*)类型的指针
    : k) d& Z0 L+ ^3 x2 Cint** pp1 = &p1;  
    / {* S! I" p6 H2 @4 |) e1 J  x- app1 = &p2; // 合法, # h' L( P+ V; y7 u
    pp1 = &ct_p1; // 报错! 类型不匹配。 (int*)不能指向(const int*), B6 A6 h. l; W2 [
    5 v* y& N3 y& @, S2 ^( L% V: a6 f
    // (const int) * * pp1; 指向((const int) *)类型的指针
    ) p# g2 v% y% pconst int** ct_pp1 = &ct_p1;  ( \# \% @$ R2 P, t- ^% H0 d
    ct_pp1 = &ct_p2; // 合法
    ) c7 L& G8 F5 |2 z$ {ct_pp1 = &p1; // 合法!(const int*) 可以指向(int*)类型。: ?9 t7 Z( K0 Z# p4 q& U
    ( `/ _7 p2 S% N2 ]& x# p6 o3 I$ O
    // (const int) (*const), x' D& @, L! ]3 p# T2 J3 m) }
    const int * const ct_cp1 = &a; // 指针也不能修改
    8 }5 V* j: L3 U' n3 i# G, Pconst int * const ct_cp2 = &b; // 指针也不能修改
    6 y# E4 D5 T; l6 K+ ~ct_cp1 = &b; // 报错!指针有const修饰$ `+ L# m% F5 s) R3 Z) Q0 P1 c

    % E3 N9 v2 j$ I& g// (const int) (* const) *  指向((const int) (*const))的指针
    9 Q1 K) U' G% g* bconst int* const * ct_cp_p1 = &ct_p1;  + s( t" ?4 E" G0 C; V1 @0 g' J2 D
    ct_cp_p1 = &ct_cp2; // 合法, 指针的指针并没有const修饰, 指向的指针有const修饰0 ^+ J3 C5 b& o# M
    *ct_cp_p1 = &a; // 报错!等价于操作ct_cp2,  指向的指针是带const修饰的不能修改# F( n' t! ~8 ~9 ^) N

    2 k* j& J' ^& q// (const int) (* const) (*const)  3 F* v; ]# D6 L; W( ]* [" H
    // 指向((const int) (*const))的指针,且该指针被const修饰
    : B1 K  [( G, V: I6 w. H1 Sconst int* const * const ct_cp_cp1 = &ct_cp1;
    / e8 b; y: G7 ?7 bct_cp_cp1 = &ct_cp2; // 报错! 指针的指针被const修饰, 不能修改指针指向。9 q" P8 H$ e# c* h
    6 T& `! a. L) s* v# f+ T" R4 O
    一行声明多个变量: T: |. g8 b4 C! m
    类型 + 名称定义一个变量。: m; w% x% I* J& z8 w
    变量的前面可以加*号修饰, 表示指针, 一个星号代表一层间接。**表示指针的指针。: ^+ T' L0 ~3 I
    & v( W- [+ c% E* c7 n0 P1 v
    int a, *b, *c, d, **e;0 o: @1 Q! }1 P5 |% P
    a = 0;' t5 V: G3 C' i$ p/ G
    d = 1;
    + L) C9 F9 ]( bb = &a;- A) i- L5 G% e( \6 {! f" o
    c = &d;9 }- B! m' ?4 i) V3 @
    e = &b; // e为int**类型 指针的指针
      ?& h# T+ k$ R* V) we = &c; // e为int**类型 指针的指针$ R9 R9 L; D2 _1 [4 Y& a6 y8 L; o/ ?
    也可以用括号包围变量和*号。
    , u6 d2 T" x1 ]
    2 I1 T: G. G! b( Z  a  w7 c8 w# |- Tint (a), (*b), (*c), (d), (**e); // 合法定义。# \: v; o0 C8 x+ O; m) C' A* \5 a
    括号可以省略,某些情况, 个人感觉加上括号更清晰一些。例如. R( w7 C$ w6 A" A

    ! `" R  u5 ]$ U5 \7 s$ U( Eint (a), (const *b), (*const c) = &a, (const d), (const* const* const e) = &c;
    6 D7 m# y9 \/ w# g写成
    + n- J9 J% f: A/ W; O( y
    2 B# r% i* K) ?8 f! z5 K1 T' R  ]8 wint a, const *b, *const c = &a, const d, const* const* const e = &c;$ F; F$ I3 h+ P+ {* j6 t
    更重要的是, 后面我们表达数组指针,以及函数指针时,括号是不可缺少的, 带括号的表达更加统一。9 ]4 j2 p" [+ [

    0 K9 h+ d! Y/ }3 c/ v数组指针
    ; y  r- q: L: [0 p0 u6 ~5 z$ N! F  u数组基本表达
    ( v8 m$ z* ]8 Sint a[10];  // 定义了类型是int, 元素个数是10的一个数组。
    4 `  {; n4 X5 l" v# x3 A# [由于c++要支持一行定义一个类型的多个变量。 所以数组的[]时放在名称后面的。虽然我觉得* N0 d' y2 s1 ?: j0 K4 h, u' k
    9 R( r8 R1 J. B4 F( \0 e* \
    int[10] a;
    1 d  _0 l' h2 H这样的写法更符合类型 名称的思维, 但是如果类型都这么写的话, 没法兼容以下的写法:
    : b& J, y0 R, z6 `5 H1 s- C3 G5 e) ~6 K
    int a = 0, *b = nullptr, c[20], **d = nullptr;
    6 G' y: _7 Z, P( B$ Yc++标准规定如此,但我们可以通过每一行只定义一个变量的写法, 类型会更加清晰。
    ! G& Y! z2 {4 I' v$ v( V/ i
    / X1 p% v6 O+ m; ]- nint a = 0;* Z$ \/ A& _; i0 f% e7 Z  N8 f
    int* b = nullptr; // 指针int*2 L  J7 i+ P; M# ]& x5 L5 g1 j1 f
    int c[20];5 [  T1 x' z* i* O# l
    int** d = nullptr; // 指针的指针int**
    9 T" m4 _, \4 [  o" z* J数组的名称是什么类型0 {. D7 I7 N. U# g" g3 R
    数组元素类型的指针,可以直接指向数组。 并且数组跟指针一样,可以通过下标去访问元素。
    ' {1 B3 n! {: g/ j$ y* `, c
    6 M5 R$ n; ?! e8 ?4 Sint a[10];
    3 P) c: }! [, Aint* p = a; // 指向a数组的第一个元素
    & K, x0 o  H' r: ^a[1] = 1;
    ( m4 Q* A% R9 B$ B6 zp[1] = 1; // 效果与a[1] = 1一样。; M, G- S2 u/ A  X  t5 m! o
    数组可以当作T* const来使用, 但是又与T* const有些不同。sizeof()的结果不一样。
    1 ^" ^- |/ f. y1 j/ {4 _
    , |8 b& R2 W+ V+ K; Mint a[10];$ r4 R; Y- ]# e; X/ p  f+ q
    int b[10];
    5 A/ u' x0 q9 Eint* const p_a = a;
    & J3 O  P+ Q( r( ha[0] = 1; // 合法。 数组的元素可以修改。
    ! A; W8 J6 U7 {9 `p_a[0] = 1; // 效果与a[0] = 1一样。0 @) D  P* W1 j8 X
    / x, V1 i* J. O" p# ?9 y( f
    a = b; // 报错! 数组本身的指向不能修改。. \3 S4 l# k) N# f

    - k  d7 {' U% Z) H# |( z8 r// 所以数组a可以当作int* const来使用
      B8 i$ o1 L/ b0 r) y! bint *const& ref1 = a; //正确。
    9 A6 l4 z% \+ q' Q, Fint *& ref2 = a; // 报错!
    + H; O2 H6 H6 e# Z
    ( s' |  d& y7 h; c// 但是又跟int* const有些区别。: I. N, ?5 l5 r! w
    assert(sizeof(p_a) == 4); // 32bit程序。
    5 l. o# z  r7 l- J7 A/ Rassert(sizeof(a) == 4*10); // 32bit程序
    9 V% |: `( g2 p6 \
    ! c- t3 Y; L4 F" @数组跟元素指针的作用很相似,都可以通过下标去访问元素, 但调用sizeof()函数的结果不一样。元素指针的sizeof()返回值是4(32-bit应用)或者8(64-bit应用), 数组的sizeof()返回值是数组实际占用的空间。数组可以当作指向第一个元素地址的T* const来用其实就是我们常说的数组到指针的隐式转换。当数组作为函数参数传递后,会自动退化成T* const, 在被调用的函数内部调用sizeof()的返回值跟T* const指针大小一样。 数组传递作为函数参数后, 在被调用函数的内部与T* const是没有任何区别,只有在数组定义的可见范围内sizeof()才有获取数组占用空间大小的效果。
    $ z. A' s. U9 J% a; w0 y
    ' Q0 Y$ @4 C' b7 g以下3个函数翻译成汇编以后,汇编代码是一样的。
    0 c/ @' h) y. i2 A7 R: n, X1 H" l/ K6 Z1 M* ~" c! u
    void Func1(int* p_ary)
    , K* ^: G4 P" N( T2 N! B. G0 f{9 T" Q* S2 u' B$ l- A/ A4 Q' e& p
        assert(sizeof(p_ary) == 4); // 32-bit/ ?7 A1 r& g* u+ ^9 \7 ^
        p_ary[1] = 1;
    ! \$ E6 L& A9 q7 n* j" j* G' W}; [/ I" h4 m8 |+ q; b3 o

    7 f$ i% M% j0 i' Z3 jvoid Func2(int ary[])
    6 p8 i* ^8 |, f2 b{  x9 I4 y5 L* y
        assert(sizeof(ary) == 4); // 32-bit
    ; ?' h6 K1 k) x) H    ary[1] = 1;0 d0 W  u4 ^! V
    }
    ( ?9 X9 R+ L6 w  M( o3 s
    ' X/ }" _2 W/ M- _  Fvoid Func3(int ary[10])1 i7 I7 j+ ^5 L( c! I
    {' X3 x1 `, r7 X# x4 `$ m
        assert(sizeof(ary) == 4); // 32-bit
    & l: R+ t. G2 ]; Y7 D3 P* K+ ]8 J    ary[1] = 1;* h* k2 ]4 q9 k; _+ j' ]; R
    }
    8 }5 G3 q5 d, U" F4 Y( E
    + C! w% l3 F" n) n6 [int main(int argc, char** argv)) t5 y! p3 W2 E! r
    {
    : Z% s4 ~0 E- b: \6 j' [4 r    int a[10];
    , \  u* S: a$ f    int b[20];
    9 M" U7 S' v" ~: h    Func1(a);
    : e% M/ h8 q! i9 w' p6 l, m    Func2(a);' Z  q' J& P5 J+ }# A
        Func3(a);$ D; n0 g2 q! s$ D- M  g
        Func3(b); // 退化成int* const了, 即使数组长度不匹配也不会报错。! l% O" J/ b6 l. i- _: l
        return 0;) p: d% J/ ?7 ]5 k# b
    }
    * d8 ]7 O. b( Y+ V" o) H. Q! O' a  a. m' K$ n9 B

    $ m0 V7 G6 D' G) j& ^/ ?+ A; f( \8 e
    8 S" u* f8 d3 ~* h, \! l多维数组$ `  S) }" f9 K8 L8 {2 S
    一个3行,4列的数组, 结构如下:* t" T5 J* v, ^' R1 c! ]

    8 B( R; m: B3 E  T; [# Uint a[3][4];
    ' D6 `; ~$ W! Tcolumn 0        column 1        column 2        column 3
    9 c- j8 O* i; k2 Q2 ?: Urow 0        a[0][0]        a[0][1]        a[0][2]        a[0][3], @6 G7 k" I; N
    row 1        a[1][0]        a[1][1]        a[1][2]        a[1][3]
    - C7 N6 h$ M. i8 N7 M7 _row 2        a[2][0]        a[2][1]        a[2][2]        a[2][3]$ g" Q# J1 Y: d- I1 ^' v* x( K. ~3 u" m
    数组初始化
    2 W8 H2 w7 s7 t  s
    ( ?: n8 J+ M$ i  S- b5 l4 b" {. Nint a[3][4] = {
    / {$ e3 v9 Q, X* q( p6 E1 o9 m) O    {0, 1, 2, 3}," ~% r3 Q  r% g- }
        {4, 5, 6, 7},+ L+ \- h3 h" l% s6 |8 t+ l# Q
        {8, 9, 10, 11}
    : N7 q' A: @0 U' _! d% ]! b+ ^- g( ~};1 O" F3 M/ d: M
    实际上多维数组和1维数组在开启速度优化后,翻译成汇编代码是一样的。8 Y# m; H/ o: y9 \
    7 S; N9 t/ U4 w4 @( I: N
    void Print(int* p_ary);, r" ?4 |) O9 n" I0 @9 O) G9 k, B
    % d' \0 f, s: V1 n3 n# m
    void Test1()2 y7 q8 N* c( Z, _! d' C2 X
    {
    / h7 w; ?/ d  }  E    int a[10];
    ' v# o+ g4 E$ w7 d$ H    a[3] = 3;
    7 |5 a$ E( U+ |: P; h8 O5 ^    a[7] = 7;  p7 Z( \$ z' I- c, S* h# @& o! ?
        Print(&a[0]);
    8 Y/ j& J$ I6 Q7 |; a}
    : `, ~& x6 n9 k7 r7 u9 w' I. }5 b5 h% y
      C8 T3 T* P8 q- dvoid Test2()$ ?) J: \1 i# D( h& y2 L
    {
    , R  `) g' h! e    int a[2][5];6 J, ]" f! D/ [: M" T( i0 c
        a[0][3] = 3;/ v( s2 A/ |( v- h& Z. c6 }4 |1 R% q
        a[1][2] = 7;5 V9 [0 S# r; l6 `* R
        Print(&a[0][0]);
    % G: @$ L5 m2 D7 a$ C}
    * D; g( B- d$ z9 N+ l) J9 t6 f+ l5 ?  D8 s5 K. O

    : F+ y1 c6 W4 v7 ^7 S; R2 ?* e0 L) i* L
    很自然地,多维数组也支持用1维数组的方式去初始化。. s2 {7 {. s  m7 [9 @) ]2 f

    4 F1 y; [$ I7 ]5 `5 h5 O, @int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
    9 _9 ~: t& ]& k: X9 t既然多维数组与1维数组没什么区别, 为什么还需要多维数组?
    ; X. W( r8 Y3 N5 m. O
    3 E0 G1 T: D, \* r3 d% y假设有一幅RGB图像720*576个像素,每个像素有RGB三个通道,每个通道的值是8bit大小。给出图像的首地址p_rgb_image, 我们要取第40行,第50个像素的R,G,B值。代码如下:
    - o9 m9 C  z- R& u8 J1 ?
    8 r' C# F' z9 ?! X2 Eunsigned char* p_rgb_image;
    : O$ U- ^4 ?( q- g8 e" b+ cunsigned char r = p_rgb_image[40*720*3 + 50 + 0];2 h* N. b; H0 L. }
    unsigned char g = p_rgb_image[40*720*3 + 50 + 1];
    5 L3 Q! o- ~  Q+ qunsigned char b = p_rgb_image[40*720*3 + 50 + 2];  Z1 v. X6 Z7 l; V
    类似这样的场景, 采用多维数组的写法, 有点类似以索引为参数,可读性更高。相当于程序员和编译器打了一个配合。
    / C3 U; l7 Q6 ^7 x  a* M
    ) S; R% [2 O3 h& j: ?enum6 b" }3 M" D4 n# _$ |1 ?% y
    {- j# g- p9 {" V' w+ B
    Red = 0,
    ) V4 U3 O! G0 U) T Green = 1,1 g7 P2 B5 D+ }$ V7 G
    Blue = 2
    & l0 S6 ?8 Z2 N  @. H2 R};5 |- i/ u9 [$ s9 ~) v
    unsigned char rgb_image[576][720][3];7 V+ J9 O" r  o* Y( @! ^
    int row = 40;/ o5 j- s4 j( D7 G1 i0 M  i$ z
    int col = 50;  W1 t2 d3 _) q2 I% _1 B! S0 D
    unsigned char r = rgb_image[row][col][Red];
    ; o! ?. c( J/ K, A7 H, Iunsigned char g = rgb_image[row][col][Green];
    8 G, a9 ^0 ^8 |5 l# n* ^unsigned char b = rgb_image[row][col][Blue];2 s0 w1 g6 l9 A/ g/ z
    数组指针以及与指针数组的区别
    . ^2 |# ^$ r$ F+ P* n数组指针,是一个指针, 指向的对象是数组。 数组指针的赋值,要求数组的长度匹配,否则会报错。当指向1维数组时, 需用用*取得数组对象的引用,再用下标来访问数组元素。, u+ x% S" g7 C% W2 |) ]& S; }  ^
    指针数组,是一个数组, 数组保存的元素的类型是指针。+ [* A3 \/ f; p/ u6 D4 L
    数组指针的定义
    $ o+ @. d, ~- n: a) m( W1 u$ H# X数组指针定义先定义一个数组。
    , d  @- H% `. F2 M0 Eint a[10];. B- D5 W0 {0 C, ^( ]+ V
    然后对数组里的名称用括号括起来后再在变量名称前面加个*号7 H9 N) A1 n5 v0 }; ~8 A: B
    int (*a)[10];
    / I' [* \  C+ K- m- R1 y7 e后面你会发现函数指针定义类似。
    % W. z' I: n3 \9 r$ y5 {// 各类定义对比# J7 t' M5 D" y2 {! r7 p4 @
    int a, *b, **c, d[10], e[10][20], *f[10], (*g)[10], *(*h)[10];
    % g( ~, q. O1 [6 l6 [% D, h$ D3 w- P  r! v  y! S: G2 S# V( b
    int *f[10]; // 指针数组, f是包含10个元素的数组, 数组里每一个元素的类型都是int*9 w( C# ?0 H2 A* @! i/ J
    int *(f2[10]); // 指针数组。另外一种定义方式。
    6 ?# V0 _* i6 k+ bint(*f3[10]); // 指针数组。另外一种定义方式。+ A  S7 P# K- e8 E  W+ J7 ]8 m9 e
    int(f4)[10]; // int数组
    5 W. ]" z' T- t# y: A' iint(*g)[10]; // 数组指针, g是一个指针, 这个指针可以指向类型是int,元素个数是10的数组
    + ^- n. Z# m; H( h9 o4 n  R+ U9 Qint* (*h)[10]; // 数组指针, h是一个指针, 这个指针可以指向类型是int*,元素个数是10的指针数组2 _5 G' e) [3 L; N5 g% L: K
      A! M$ l1 C' l8 j* _
    int d[10];
    3 `  `( l  _5 X2 dg = &d;
    - L, {' M: |- u7 {6 l5 G% e4 ?6 |; c; B, ?
    int* e[10];, Q9 i4 I& a2 w$ ]! y2 `) Y
    h = &e;+ ~4 k) N4 @; N1 a
    数组指针的使用# U7 s! E6 c& n. {8 ~4 \) }
    数组指针一般先通过*号取得指针指向的数组对象, 然后再用下标操作访问元素。4 T  E, }, v- G. ^5 U7 K
    1 y- N/ z7 m  N4 P/ r0 F
    int a[10];5 z: G0 F9 P1 {. A
    int(*p_ary)[10] = &a; // p_ary是一个指针, 指向"int (*)[10]"类型的数组- {$ P2 l1 E: V- T: e# [
    for (int i = 0; i < 10; i++) {
      S' s2 b1 N8 k, O# b. C // p_ary是一个指向数组的指针, 需要先通过间接寻址运算符*(indirection operator)取得数组对象, B* Z/ J% [$ U' i
    // 再通过下标操作访问元素。, C, O# {( w, [, ~5 p% H: I
    (*p_ary) = i;
    . h* j1 U0 _9 o0 h5 A/ s}
    ) t9 i4 w2 c1 S' w* R, G$ ?1 N  J6 i
    int b[10];. S8 {) X" t# W
    int c[20];5 V' z( C9 ^' I# a1 w3 a
    p_ary = &b; // 合法
    & l+ ^2 p1 c! F  Qp_ary = &c; // 报错! 不能将 "int (*)[20]" 类型的值分配到 "int (*)[10]" 类型的实体
    / J) `$ c+ f! R  |" G+ D$ J, m% K' L! N数组指针指向多维数组的子数组
    3 [1 h. s- s: D/ H9 ~! gint a[10];
    / T2 v# G' J3 uint b[4][10];, M7 V* o; a1 i' C4 K
    int(*p_ary)[10] = &a;+ {6 m. m  _9 O; O) Y
    for (int i = 0; i < 10; i++) {
    5 m4 B- d8 K/ Y' c, M+ p- V (*p_ary) = 1;
    " |- P5 k8 k5 M/ T+ n4 a}1 j2 b! O1 O% K% A  u) m! f

    , I3 H9 Q1 P* X, f' |! O. ]9 @p_ary = &b[2]; // 多维数组,可以看作数组的数组,
    ) a( V8 T" m4 \9 C& M2 S, Q// b[2][0] ~ b[2][9]的值都被改成2了7 ]1 Y. a: F+ d- i" z  P- w& _
    for (int i = 0; i < 10; i++) {
    : p8 d  y2 P5 x- m% s: C (*p_ary) = 2;
    ( c2 `, ?" N# ?7 d}
    : ?9 |" X# A+ h* C0 L( p4 ?多维数组指针
    * h" I8 m" J3 r多维数组指针,是一种指针,指向的对象是个多维数组,支持多个下标操作。  v" z- `/ M1 \$ q
    2 U/ \( _  R0 k9 c. m$ o$ s! ?
    int a[2][5][10];, i4 k' _, I/ N) f* X
    int(*p_ary1)[10] = &a[1][2]; // 1维数组指针
    ! c. K2 D. b' zint(*p_ary2)[5][10] = &a[1]; // 2维数组指针1 x) I" W, x+ x: b9 q# w
    for (int row = 0; row < 5; row++) {
    0 z! V3 J. ^2 {/ P    for (int col = 0; col < 10; col++) {
    4 t) c  `+ t$ D6 f, n4 h2 @        (*p_ary2)[row][col] = row * col;* S" X8 N8 a) T+ k9 G/ ?
        }7 s! O! V) U' A  E$ W) V
    }# i  {0 W# @) C" w. C3 c! d
    数组指针和指针数组对比实例7 w. \- G4 a; J9 C
    数组指针还是记住两步法即可# s) W( }1 w$ Q$ S8 ]

    : i0 q2 L4 X  o- r$ Z5 ^) r定义一个数组
    3 R2 T0 d1 g  z/ ?( d括号包围1中定义的名称,再在名称前加个*号。
    9 l4 M! c5 ?# B, r  R% Oint a[10];
      @# {" [) k# O6 x6 X: a( Gint(*ary_pointer1)[10] = &a; // 数组指针
    8 d8 Z% F; `; N# u  c0 gint* pointer_ary1[10]; // 指针数组。元素类型是int*
    : Z+ U1 w7 Q9 j- z+ Zint *(ponter_ary2[10]); // 指针数组。另外一种定义方式。
    : Z3 ]% g0 Z! a$ g+ p( lint (*ponter_ary3[10]); // 指针数组。另外一种定义方式。
    % \. d& x* C5 L6 x4 Hint c, *d, (*ary_pointer2)[10], *pointer_ary3[10]; // 排列定义比较。2 k, ]0 x' U( G' ~
    ; `! x* o: q) d1 W* m5 T, K+ o( E
    // 指针数组可以把每个元素指向数组对应位置的地址。4 S$ r& k- ~* k' ?/ ?* I% b
    // 这样遍历指针数组, 可以达到遍历数组元素的效果,但是注意每个元素都是指针,
    % {! y/ ^/ J9 K! {" |// 需要访问原数组的值的话, 需要对指针用*间接寻址运算符。
    2 R0 a# i5 I: f& H; V  Qint* pointer_ary[10];
    , I3 }; l  f! p& J) |: y, l( \for (int i = 0; i < 10; i++) {& }" q( y  F8 j( b# X( m; A  u* I3 m
        pointer_ary = &a;* q$ n  [# T# D/ d+ y0 l" @7 G
    }
    * C. b- Q/ ~6 @// 类似遍历原数组效果。
      J! i9 Q: L/ {: \4 s, N/ X% i: I, rfor (int i = 0; i < 10; i++) {
    " P8 `$ Q# J% E1 q6 b    *pointer_ary = i; // 修改原数组。
    7 d9 S+ R2 B  k  f}# _$ e# Q$ G$ ]" k5 P# v
    - n4 ?( P: o( j2 Y! \
    函数指针1 {- x% ]1 P7 B& G6 Z
    取得函数地址: }( i- t0 y* a$ I* I
    函数的名称作为参数被传递时,会隐式转换成函数指针, 和在函数名称前加取地址符&等价。建议带上更加统一和清晰。  X! P6 L1 d2 V2 Z; o
    - B" j$ P3 L% @: D
    void f(int);
    4 q. q: g- V2 S/ z4 Z0 f. F. Gint main()) P( w5 z6 e7 v0 I6 L
    {# ^3 H3 ]  D& f. d0 B* {6 p
        void (*p1)(int) = &f;
      L: \/ y/ E/ s: L9 V    void (*p2)(int) = f; // same as &f
    ( B2 Q/ Z2 ~2 x    return 0;
    6 o* U2 p9 ~. u0 a( ?! T3 d' \4 a}; H3 _3 |/ T! J% G2 N) N/ W
    翻译成汇编代码, p1和p2的赋值是一样的。
    9 z, ?3 \  a# v! n" g4 q/ Z9 P; N0 x! G0 S0 c: f5 M
    1 a! v3 @4 l8 S5 l9 Q! N
    0 [  M$ S4 ^5 \9 g
    函数指针的声明( z# k" e# t8 R' |5 x
    单个函数指针变量定义步骤
    6 N8 H( u9 ?. n  J; z' k定义一个函数。void fun1(int a, int b); int fun2(double a);
    % y8 M! Y5 e8 s用括号把函数名称包围起来,然后在名称前面加*号。void (*fun1)(int a, int b); int (*fun2)(double a);/ L' R7 f5 D' }6 d+ i- o
    如果要定义函数指针数组,在定义单个函数指针的基础上,在名称后面加上[数组长度]void (*fun1[2])(int a, int b); int (*fun2[10])(double a);
    0 t+ R4 _7 {# ]; V1 _8 X: y$ itypedef定义函数指针$ C5 e+ ?0 O0 I5 }
    可读性高比单个定义要高,特别是声明多个同类型的函数指针,或者函数指针数组。
    + R4 b5 R4 d/ I
    % i8 l5 [* r" Ztypedef定义函数指针的语法4 j; N1 G5 Z, x- M# x2 T
    typedef有两种做法, 一种就是定义一种函数对象,另外一种就是定义函数指针。用法稍稍不同,效果是一样。其中函数对象不支持赋值, 但是支持引用。$ ~$ ^. P7 @3 w6 R% u' n

    7 S" c; o0 E! c" f- ~# {, Y, Ptypedef int FuncObject(int a, int b); // FuncObject类型是函数对象
    " [; i9 [  k4 p( xtypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针
    , |, p! E% H, y# |5 d  p7 [FuncObject* f1 = &Add;
    - o3 P, K0 W0 b+ d1 kFuncPointer f2;! U& a% R% f) }  v: y0 k
    f2 = f1; // f1, f2类型一样, 都是形式为int(int, int)的函数的指针。
    1 U3 z. o+ D- I8 ?# WFuncObject f3 = Add; // 报错! 函数对象不支持拷贝
    6 o3 H2 _; F0 D* q5 rFuncObject f4 = &Add; // 报错!&Add是函数指针,与函数对象类型不匹配
    * e" E3 t( S4 g$ WFuncObject& f5 = Add; // 正确/ B! `* B) J+ A4 B4 }
    int ret = f5(2, 3); // 正确# i1 V* o: |: |8 Y2 Y; |6 [
    FuncObject& f6 = &Add; // 报错!&Add是函数指针,与函数对象引用类型不匹配) G. p% n2 H6 j) ]0 j1 [7 z* _
    如何记住typedef定义函数指针的步骤* J9 _0 X8 p( z4 `, z# _
    像定义一个函数指针那样, 指定一个名称。int (*CalFun)(int a, int b);# z! S0 `8 J8 y. J+ e* b; `$ S6 T$ ?
    在这个函数指针变量声明前面加上typedef。typedef int (*CalFun)(int a, int b);1 T) y9 m9 l. K% `/ K: M
    完整例子8 R0 O/ _5 O2 ]
    typedef int(*CalFun)(int a, int b);
    % i; [. m; S3 Q& d. @- b( t9 ?$ A" @) o7 G
    int Add(int a, int b)
    2 [& X1 O, m6 j& C1 u" K9 y{
    # Y4 M: ?# @6 b0 U& l    return (a + b);( n- T, I# ?( O9 R
    }
    2 F  {1 S; _& f/ e* s6 j- g
    & q6 K4 Y. o; b+ a; gint Sub(int a, int b)
      Z5 q- K1 p, G* X# W{+ ]  u; q9 a1 i( l- _# H
        return (a - b);
    9 c5 {; @8 x3 a! o6 a! o$ [}
      V+ G' W: S' `- I5 p( B! L9 Q, X6 P# h9 b2 b
    int main(int argc, char** argv)1 E( z4 H9 @" ?+ W# \
    {
    1 W; M+ X! k" Q6 O    CalFun f1 = Add;  p3 ?  S% w4 x$ p( y% f
        CalFun f2 = Sub;
    6 V& K, S/ L6 q    int a = f1(2, 3);
    * X$ M" i: G1 m) n8 v    int b = f2(10, 5);+ T, D+ L0 ^5 x

    . z* t/ ~& _9 Z* Q; V! i    // typedef定义的函数指针数组。
    + E4 y% f1 b* u. J    CalFun f_ary[2];; U$ B6 X2 A9 Y- E' ~0 m7 g
        f_ary[0] = Add;
    2 _4 ]# P1 q% u. y, r    f_ary[1] = Sub;
    ; h) q& N- U# m7 v) i9 ?; W! K5 h* a; K# F5 N& |
        // 单个定义的函数指针数组。
    " ^- Z! r* ?) B4 {9 H7 V  X    int(*f_ary2[2])(int a, int b);9 l. d  y. S) O% [6 \
        f_ary2[0] = Add;
    * g/ A- Y, J* P+ s5 q* D" |    f_ary2[1] = Sub;
    # k& d1 T  Q3 Y* T" P8 c% Z% [3 d8 O5 ]6 K  y2 t$ q/ y% y
        return 0;
    7 P. k& Z" o$ Y- {; @7 T}, \% e8 o( f* |' @% y# V/ h
      Q5 L& X' X* b' l
    using别名定义函数指针
    ' O% r; \: g+ X# L+ Z. fc++11以后的类型别名定义--using也可以用于定义函数指针, typedef的好处它都有,个人感觉比typedef更直观。using类型别名同样分函数对象和函数指针两种方式。3 h9 W$ H' m5 b- O6 S3 n
    # Z$ p! k0 ~% Y) ?( a4 \6 p! X
    typedef int FuncObject(int a, int b); // FuncObject类型是函数对象
    9 X+ @& v! ^: w' f1 e. Zusing FuncObject = int(int a, int b);
    # g$ f7 k, s; |/ v; }- ftypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针! w+ }1 r  _4 j: U
    using FuncPointer = int(*)(int a, int b);
    / B* J- ~  A" h7 Q, t1 n& H# o% I函数指针的调用) }7 A+ O5 d7 O  A  P
    函数指针和函数对象都可以直接后加括号调用
    9 ~3 R! x+ R& P1 k3 b2 Dint f();: U$ ^2 z- f. J  `- ^- S+ i
    int (*p)() = f;  // pointer p is pointing to f
    * x! N5 r- U, Jint (&r)() = *p; // the lvalue that identifies f is bound to a reference
    9 S7 A6 ]4 n3 U. k9 i7 t# K* m8 Yr();             // function f invoked through lvalue reference
    ! M6 C9 B% v2 V: q, j(*p)();          // function f invoked through the function lvalue
    6 i: `! ^& x, \/ o1 A) ^p();             // function f invoked directly through the pointer
    ; c+ Z& A. o/ D# _如果函数有重载, 函数指针会指向匹配的那个版本。
    " `4 x  f- {8 u0 F' f0 W4 u: B3 {8 Gtemplate<typename T>
    . i: s* [2 Q! r# [0 V; L/ kT f(T n) { return n; }
    5 ~5 h6 n( r1 m; {8 t
    4 H& z6 d6 C  Y8 @3 V  o* S1 udouble f(double n) { return n; }
    + Z2 s8 Z/ [/ I1 [( r# s/ w5 V
    2 D* h7 l6 }6 {7 `* j/ kint main()
    # p! T0 Y- U4 I; _/ Q{  v1 f. [( R' P! i4 H; A7 w  u
        int (*p)(int) = f; // instantiates and selects f<int>' Q5 J0 O, C6 u8 D0 N
    }
    % F) P7 h6 V, H5 b' X5 L9 d成员函数指针
    ( G) m- {  `5 ~  V# d. h1 h7 E" k静态成员函数,除了增加了访问控制以外,跟普通的函数指针没什么区别,所以普通函数指针可以直接指向类的静态成员函数。但非静态的成员函数与普通函数指针不太一样,声明时需要指定函数归属的类名,并且调用需要指定对象实例。
    5 }- C( C4 G" j& g+ s4 }8 s9 |3 p
    ) z* c7 W  g4 B' m' |) t1 j3 v- _成员函数指针定义。$ u  [. T4 r# t; M, n+ q
    像定义类成员函数实现那样写, 并任意指定名称,这里作func。void ClassName::func(int);- N& m( i. |8 Z, e/ n
    括号把类名、范围解析运算符::、名称包围起来。void (ClassName::func)(int);5 y! S$ S- X3 i
    在名称的前面加个*号void (ClassName::*func)(int);
    1 w" w; k/ T6 ~, d5 ?5 [6 x( J  ]成员函数也支持typedef和using的定义方式。typedef void(C::* MemberFunc)(int); using MemberFunc = void(C::*)(int);2 ?6 [) `: o1 B  l5 o) E1 G+ v
    成员函数指针如何调用。/ U$ q9 M' E& Z* g$ J3 y+ R' r  m9 P
    假设成员函数指针名字为func
    ) o9 J+ h; r. E( k* T/ H. K/ }9 e
      _! x- a; i; x* |9 p. V, N" vvoid (ClassName::*func)(int);
    $ C: z! s. y$ ^( y: O& X/ X3 @对象式调用。
    ( ?' K5 A5 M! |3 T' sClassName c; // 被调用的对象! _+ L' S/ E) ]; S, ]
    成员函数指针名字当作正常函数那样写。
    , Z. W  y* l) z9 f7 u& pc.func(3);7 @6 W- K4 X: W5 f6 P. ]( }+ w+ [
    成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。
    / B, b1 y' Y% B  b8 c" `c.*func(3);
    0 ^8 Y7 A  y+ H1 ^最后用括号把调用对象、成员访问运算符.、间接寻址运算符*、和成员函数指针的名称包围起来。
    7 o+ Y+ v; E; v* F1 ]# d(c.*func)(3);) m3 G4 f: t2 u5 Y" g8 S, j( ^: J. Z
    为何要加上括号? 根据c++的优先级标准,取成员运算符. > 函数调用() > 间接引用符*。 *号优先级比函数调用要低, 成员函数指针还没取得对象就被调用了,自然报错。 另外
    5 L9 z3 w) w6 {3 u- Z& z$ Z6 v(c.(*func))(3);( _- P$ m. q/ J
    这样的写法也不行。 .*和->*是整体作为一个运算符的,中间不能用括号隔开。" O( a7 p/ I5 w, c, n. u* l: |
    指针式调用9 D, G, o1 u) R! ]
    ClassName* p; // 被调用的对象的指针
    ( ~5 k) N: O7 g% p" S  q2 G9 b成员函数指针名字当作正常函数那样写。
    4 o& i2 T4 x  h( K  J6 q! J3 l1 l, \p->func(3);
    ! p# H/ j& D  q; m( Z5 N. F成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。/ e* G: K2 q4 h
    p->*func(3);
    5 k" V. A6 L4 t6 t: k最后用括号把调用对象、成员访问运算符->、间接寻址运算符*、和成员函数指针的名称包围起来。- x% [* M; [$ w3 ?+ b5 ~
    (p->*func)(3);
    5 \0 }/ C; s: l函数指针使用完整例子
    4 ^8 l. k! q$ X, x3 I4 Nstruct Cal
    2 A5 B  _4 m& b* x: U, h+ U{
    : `2 [' B: X+ d8 e5 x: l    int add(int a, int b); 5 w, L( r  n8 j$ a
        int sub(int a, int b);: q0 C% M) h* L- t# F- @
    };! |( b- d% c4 p. s+ t$ b: J& t

    * q$ d7 t0 @, d: v% _2 dint main()# B8 S2 ^9 [2 P. w: l) i
    {6 R$ @/ c2 m& c: w. U9 T& _
        int (Cal::*fun)(int, int) = &Cal::add;
    : b$ L4 y& u6 _- h    fun = &Cal::sub;- ]  @, ~/ ?6 P9 [$ K  b7 \% {
    5 s' L- [% U! n' S
        Cal* p_cal = new Cal();
    2 v- q+ e* c4 |2 z0 w' z    int r1 = (p_cal->*fun)(2, 3);% y+ M5 V. ]+ l/ G5 R5 H
        delete p_cal;
    2 R) I. ^2 l, l# A3 b
    : Q& f3 n5 l1 X; ~/ L9 n: @) E) w, y    Cal local_cal;# {$ \! A5 s& }$ n
        int r2 = (local_cal.*fun)(8, 6);& K: l6 n9 F. L# \7 ?! K8 u3 j
    }: K( U6 J9 u+ e/ m4 m, c

    $ x7 a  ]5 g" x: E, S! }成员变量指针# J0 ~9 s. c* k( i5 \2 Y
    成员变量指针比成员函数指针还要简单些,没有函数调用, 无需考虑函数调用和间接引用符*的优先级问题。
    9 C) P5 D  O/ N) L. J" x) V. C- U
    ) d# ~5 k2 \( B- e; _成员变量指针的定义
    ! h3 ^6 S3 `  p假如以下结构体C。
    , W, l$ \1 w! t4 d$ u9 {5 r
    * H7 A; j: S: h5 w4 F; Hstruct C ' J( d) w( A% Y5 Q! M) ^5 U3 ^
    {
    - T3 {. j+ @/ D: ~    int m; ' a, x+ ~) s) T) M, ^. j
    };
    5 R3 \6 ^! y" N0 |( X* V1 V单个成员变量指针定义 7 V( d. |+ K) @1 R  d; ^% C
    假设名称为p, 类似静态成员变量定义那样声明: b* Q9 C; A+ k+ O
    int C::p;
    - N. V  \2 R( D0 B: t* O在名称前面加上指针标识号*
    8 c" Y: ~. D* b0 Cint C::*p;
    6 n; Z# d' g! g' \typedef或using方式定义6 c" @9 v; e' U* K
    typedef int C::*MemberPointer;# c) Y& ?5 {$ ^* |
    using MemberPointer = int C::*;
    $ i4 V2 h; w/ _' T0 X成员变量指针的使用。
    ' {6 s. o, N2 [* \  h: [类似成员函数指针那样,直接使用指向成员的指针运算符:.* 和->*即可。* }/ J) b$ h: T- z1 P  |
    成员变量指针, 能让我们实现一些遍历成员的动态功能。 例如把一个类/结构体的多个同类型的成员变量放进一个容器里,然后遍历访问这些成员变量。+ l+ Y* _7 B- D- g5 B* r6 L
    . s  @; ?& U# h0 f. T! `+ P
    完整例子
    9 O8 ^% G0 [8 q- M5 C. h- @% estruct C { int m; };8 F. I4 E- P; @+ P% c6 s9 U6 Q
    int main()
    6 _4 s* L, ~* }3 c{
    : H, p% e1 ]: C$ {/ t* k2 Z    int C::* p = &C::m;          // pointer to data member m of class C
    # f; V4 ~- w" H    C c = {7};
    , g5 V  ^' N) ?5 N  \# D    std::cout << c.*p << '\n';   // prints 7$ ]) d8 G# V1 ]7 I* b8 U
        C* cp = &c;
    1 k) Z/ p& b5 {: U/ {    cp->m = 10;$ J  V/ s2 j$ J3 n
        std::cout << cp->*p << '\n'; // prints 10- y" Q) d; @3 J2 G/ v# h" ^8 c3 S

    " d. }2 K  A' u  `0 a* G————————————————& @* O8 T- f) t# ]  U' a
    版权声明:本文为CSDN博主「南风fahaxiki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。* L6 G; y5 n8 T( r" ]2 F
    原文链接:https://blog.csdn.net/m0_64407685/article/details/126788115
    0 i1 B& l$ S9 x: M) I8 @4 p* Y( n" S

    8 K3 W$ ~2 _  \. _+ P+ F! v( [
    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-8-5 01:39 , Processed in 0.313605 second(s), 51 queries .

    回顶部