. G" c6 d3 N# D5 S1 Lp_ary = &b[2]; // 多维数组,可以看作数组的数组, ; @4 H& R f$ |2 H) Y! |// b[2][0] ~ b[2][9]的值都被改成2了 , q2 K& ?7 ^- Jfor (int i = 0; i < 10; i++) {: F; l& f* @1 d8 s/ x0 g) H
(*p_ary) = 2; ' a; V( ~. r, r" U3 t} , I! \0 o, q9 I: o7 M多维数组指针 0 f& e) r7 V) f多维数组指针,是一种指针,指向的对象是个多维数组,支持多个下标操作。 : _$ h0 Z3 D7 N0 y # y3 g2 l3 B& _' O0 Eint a[2][5][10]; 7 T# p8 Y) Z' o8 B$ t2 e2 ~int(*p_ary1)[10] = &a[1][2]; // 1维数组指针 6 S2 n- t7 Z+ Bint(*p_ary2)[5][10] = &a[1]; // 2维数组指针 4 H+ y$ @: l: ?( R* Lfor (int row = 0; row < 5; row++) {- x: [. |" Z l( h
for (int col = 0; col < 10; col++) {2 x5 | @( E" X6 s) e; ?1 ?+ e8 x
(*p_ary2)[row][col] = row * col;+ q/ Z; i; r" V2 F- Q1 I
} 0 t: R+ n$ {* k; C}8 l% i8 Z: P) O w! b8 X. R
数组指针和指针数组对比实例" b8 a, T! A! I; `6 X$ |- @; p
数组指针还是记住两步法即可 ' T7 b& S7 v4 z! }3 D* e9 z3 N/ ?; p; }( Q; V
定义一个数组 & @8 q' g0 o7 ?9 @5 R' b括号包围1中定义的名称,再在名称前加个*号。 ; w( x! O! ^, ]1 Fint a[10]; 5 z. X, ]: k0 q" A: e( B eint(*ary_pointer1)[10] = &a; // 数组指针! v8 x& d+ M# U+ T( T9 L
int* pointer_ary1[10]; // 指针数组。元素类型是int* " q' q# i5 y5 Kint *(ponter_ary2[10]); // 指针数组。另外一种定义方式。) T. ^ \+ U" Z( O( `" |
int (*ponter_ary3[10]); // 指针数组。另外一种定义方式。 7 p2 _2 k! W% c; B* |int c, *d, (*ary_pointer2)[10], *pointer_ary3[10]; // 排列定义比较。 4 T6 Y! n5 H# t. c3 ^. l. U' O* U; f$ T q; w. s
// 指针数组可以把每个元素指向数组对应位置的地址。 0 W, n6 ^7 k8 ?! Y// 这样遍历指针数组, 可以达到遍历数组元素的效果,但是注意每个元素都是指针, 5 `- ]( }; h- Y6 `& t0 |; h// 需要访问原数组的值的话, 需要对指针用*间接寻址运算符。 7 v6 c d: ]. \/ m9 m/ nint* pointer_ary[10]; 2 U$ Q7 E, n# ^4 ^8 o* b
for (int i = 0; i < 10; i++) { 7 f$ `: t! K8 X7 L pointer_ary = &a; / v' d+ y) m0 s4 i8 G} & W! {3 t- `8 X4 R' ]7 ]( e// 类似遍历原数组效果。5 d# r& I- ^/ r
for (int i = 0; i < 10; i++) {; F1 \9 w5 c3 F! s+ U
*pointer_ary = i; // 修改原数组。3 m, m4 w8 f b/ ~: O: W
} 2 l# k% }+ m4 u 0 D" M: d+ w1 x9 ~函数指针 2 r4 q" ^5 C f1 B4 a9 W取得函数地址 / Q0 r, U- p, X函数的名称作为参数被传递时,会隐式转换成函数指针, 和在函数名称前加取地址符&等价。建议带上更加统一和清晰。 / G2 d+ m1 ~# O; Q( n; k7 _2 J) x 4 P0 v! \! V1 Y: v* qvoid f(int);9 M* L$ r8 t( T$ E, S' a
int main() # A3 I n/ d0 E4 t. i{ 2 u" U# F [$ ^3 j: l' Q void (*p1)(int) = &f; ) F( ]8 d5 l, Z' ]& _. ` void (*p2)(int) = f; // same as &f 5 J! w& u; d! W5 F5 a return 0;! i* t# m7 b' Q" @& n2 ?
}; V1 b. U+ P1 O1 h) W$ X' W
翻译成汇编代码, p1和p2的赋值是一样的。1 [2 A3 O( U- e( [; j
4 x1 }7 C8 k8 D* J0 g1 U2 k7 l0 J$ E; I* L. b
9 h# B3 J6 s+ B2 R' ?函数指针的声明4 c x! U. y. D: J
单个函数指针变量定义步骤6 Z/ j# o9 m9 I5 s& {) D! C' g
定义一个函数。void fun1(int a, int b); int fun2(double a); 3 B% e% ~' X- @( j# i用括号把函数名称包围起来,然后在名称前面加*号。void (*fun1)(int a, int b); int (*fun2)(double a);) ?1 \3 Y; v6 n0 R
如果要定义函数指针数组,在定义单个函数指针的基础上,在名称后面加上[数组长度]void (*fun1[2])(int a, int b); int (*fun2[10])(double a);0 O- P' j, a: ~' u( X% c) _
typedef定义函数指针+ c% ~' y0 ~" R& G2 \0 _
可读性高比单个定义要高,特别是声明多个同类型的函数指针,或者函数指针数组。 5 J( t% C! R- Z c* c, u- V. D% w4 a- e* C# w$ ^4 y
typedef定义函数指针的语法8 P0 a; C( b& l$ r; h
typedef有两种做法, 一种就是定义一种函数对象,另外一种就是定义函数指针。用法稍稍不同,效果是一样。其中函数对象不支持赋值, 但是支持引用。4 t' L. H3 u$ E6 H" s7 t' Z" ?' f
3 |1 H& u$ _0 X; y6 T5 H! x
typedef int FuncObject(int a, int b); // FuncObject类型是函数对象 8 O0 c5 s7 h+ ^" q7 _% k0 A* rtypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针) C" |7 X2 R$ ]. ~9 e1 X6 y
FuncObject* f1 = &Add; / E8 o2 [- M7 w8 a6 U" b DFuncPointer f2; 9 S8 q/ x1 G9 l/ W G0 D0 Ff2 = f1; // f1, f2类型一样, 都是形式为int(int, int)的函数的指针。2 E, x( k; M; {# X K# M' U
FuncObject f3 = Add; // 报错! 函数对象不支持拷贝9 e$ g( b! n3 a" ^3 l3 l2 P! F
FuncObject f4 = &Add; // 报错!&Add是函数指针,与函数对象类型不匹配6 f' ]+ z* g2 i2 r1 F+ T7 B p$ O
FuncObject& f5 = Add; // 正确 . t( ]3 [6 U+ l# a' t7 g9 J2 m3 sint ret = f5(2, 3); // 正确 3 @) F1 w, b) M; F$ j2 p) ?- LFuncObject& f6 = &Add; // 报错!&Add是函数指针,与函数对象引用类型不匹配! V/ ?' y; v1 l" ^8 c
如何记住typedef定义函数指针的步骤 # N& W& w# ^ l' v- j像定义一个函数指针那样, 指定一个名称。int (*CalFun)(int a, int b); v% b8 m- i; e! C+ ?: j在这个函数指针变量声明前面加上typedef。typedef int (*CalFun)(int a, int b); 9 i" X- X4 @" D$ e4 K- N完整例子; p9 N- d9 f% Y( M$ K& A) z
typedef int(*CalFun)(int a, int b);: d5 _7 [4 X1 a, Z% J w6 A
) U0 W. l4 x( z4 T" j# yint Add(int a, int b) * O' U% g+ m! C- R- }0 H{ + S8 h9 _. K; C* d return (a + b);% d9 k, ^7 X* Q9 v; B. C4 e* t
}- U0 v5 `: w% T5 N2 t
, H( s7 x8 ? S% U
int Sub(int a, int b) 7 b+ m. u3 c! t) @% N) w{* J0 K3 N H# A: G
return (a - b); . ~4 `; h/ U0 c, b9 @, U6 W2 s$ e}. t% T& E, k" |* S' W5 v
( a, _: G4 a! q. d0 u1 }) A( ]7 d // 单个定义的函数指针数组。 * {7 n- b- C( j# w } int(*f_ary2[2])(int a, int b);8 @$ B" y% T7 ^( Z
f_ary2[0] = Add;" m; H/ y0 ^7 w4 C# ~' I
f_ary2[1] = Sub;* a# z0 G9 C% [% p
7 L8 P4 k7 g0 R3 s" g( L return 0; & ^& z8 V7 `) Q5 \+ I' s" o}1 y8 J) s/ L0 v: R
; K O! L; o! }/ r. F
using别名定义函数指针" a' t3 x! x) l Y# d5 m
c++11以后的类型别名定义--using也可以用于定义函数指针, typedef的好处它都有,个人感觉比typedef更直观。using类型别名同样分函数对象和函数指针两种方式。; a+ o. Z* d# P- z6 f
4 [; s. s1 n x; v
typedef int FuncObject(int a, int b); // FuncObject类型是函数对象* f' W! T% d- p) k6 W* M' S
using FuncObject = int(int a, int b); # w, A4 Q2 O( t3 K4 ~$ \7 j$ |0 Atypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针$ w3 I+ R" D& k+ X$ ]
using FuncPointer = int(*)(int a, int b);# ~3 @" J& R e; j# ~; ]7 z
函数指针的调用 ^: S" o& p- T+ Z" ^4 G函数指针和函数对象都可以直接后加括号调用* f# Y" M# L& F$ P3 x8 ]
int f();, Q/ e7 A3 Z5 ~$ _( R. s [
int (*p)() = f; // pointer p is pointing to f8 H$ i& ~9 j3 e
int (&r)() = *p; // the lvalue that identifies f is bound to a reference ; S# X& z+ B- C0 r2 U( L9 S: D- Jr(); // function f invoked through lvalue reference, O% O# f6 c. c5 N$ ~$ j" |8 B
(*p)(); // function f invoked through the function lvalue . \! j; J% D8 ~1 ^0 p' Y) Mp(); // function f invoked directly through the pointer* V1 s/ { b( ?: A8 n
如果函数有重载, 函数指针会指向匹配的那个版本。 2 d5 m9 x/ N* Ftemplate<typename T>- b) y$ a, h7 f# d N$ ]3 }
T f(T n) { return n; } * x. i1 q) B; S8 L! u) w- C X: u/ h7 S; v
double f(double n) { return n; } $ K4 V& b+ h P( R O% N0 S* |# L) D; X$ n' N
int main()& G `5 k" N/ s; Z; W: S3 j8 k6 _# B
{ - e9 @; }* Q0 y+ \0 f int (*p)(int) = f; // instantiates and selects f<int>) ~ O& Z3 X' Y! _' J" i
}" P! r7 Q& {. L w* s# x+ s
成员函数指针 & ~3 \* j1 v3 G7 P6 V9 U6 {( G静态成员函数,除了增加了访问控制以外,跟普通的函数指针没什么区别,所以普通函数指针可以直接指向类的静态成员函数。但非静态的成员函数与普通函数指针不太一样,声明时需要指定函数归属的类名,并且调用需要指定对象实例。 . a- ]+ u9 ~. k+ ~; o, ]3 Z3 w8 v/ C% f4 c
成员函数指针定义。; q) W3 X* S0 C7 Y, M
像定义类成员函数实现那样写, 并任意指定名称,这里作func。void ClassName::func(int);/ d7 j( J' R8 k' M. r
括号把类名、范围解析运算符::、名称包围起来。void (ClassName::func)(int); & j0 I/ d- c0 w在名称的前面加个*号void (ClassName::*func)(int);$ N3 Q- J8 k; C" v0 F
成员函数也支持typedef和using的定义方式。typedef void(C::* MemberFunc)(int); using MemberFunc = void(C::*)(int); ( k& L8 |5 e6 F/ N% @* M E9 B成员函数指针如何调用。3 N, z! ^4 n; `$ y; ^3 i9 C
假设成员函数指针名字为func. h+ M9 _5 V, V2 ?4 f
7 N) c4 E( o5 X3 j- e; c8 Cvoid (ClassName::*func)(int); 0 ?! A1 x, v* o T6 m/ k9 U+ q对象式调用。 , ?- K6 q6 g" l/ ] B. W v# I7 BClassName c; // 被调用的对象 1 i/ i# [/ _5 w7 ]成员函数指针名字当作正常函数那样写。 # s* F2 m. [6 Lc.func(3); 4 G( k& A0 ^/ W( _5 ]- v0 Y成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。 ; H. P6 q, r% Z4 a7 cc.*func(3);9 J- ?/ C) h1 S( k. E9 a% b
最后用括号把调用对象、成员访问运算符.、间接寻址运算符*、和成员函数指针的名称包围起来。 8 ~ P- f* p8 {3 K# ]3 l(c.*func)(3); * T+ o0 x& q' h, t& F+ S( ^为何要加上括号? 根据c++的优先级标准,取成员运算符. > 函数调用() > 间接引用符*。 *号优先级比函数调用要低, 成员函数指针还没取得对象就被调用了,自然报错。 另外0 \. r9 U+ y7 P. S/ v0 I
(c.(*func))(3);- X. z( W. z& t0 [! }/ q
这样的写法也不行。 .*和->*是整体作为一个运算符的,中间不能用括号隔开。 % X: u2 W# j/ o2 x8 P指针式调用7 m1 n) U! Q' [" }
ClassName* p; // 被调用的对象的指针 6 V4 F$ D* \3 |成员函数指针名字当作正常函数那样写。 $ k3 h# L% K! d: W- p. t/ K* qp->func(3);, F4 s; @4 C9 j, Z2 ~5 D2 f' d8 s
成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。 X) t) I* D0 c! r; X* _p->*func(3);1 f9 G9 L7 v" t+ b' O
最后用括号把调用对象、成员访问运算符->、间接寻址运算符*、和成员函数指针的名称包围起来。1 I$ N( f$ K# w+ @: j/ d
(p->*func)(3);' |: u K" O( d6 ~' n6 Y
函数指针使用完整例子 " U; v. I/ b, u5 q+ ~struct Cal 8 E+ k) m) D8 f{ 2 r$ [1 V5 [' O7 [/ v9 t$ L
int add(int a, int b); * {% M, ?: V i
int sub(int a, int b);0 H/ h4 |! S$ F1 ?, `9 C% s
};. O7 z' k3 s: _) S$ f0 H
" p3 Q3 O1 ]# A2 {9 dint main(): m! y% C. J* b+ t2 R% y
{ + X6 K2 G6 w& y% p3 Y4 P1 ` int (Cal::*fun)(int, int) = &Cal::add;9 _) e7 Q$ A* u S
fun = &Cal::sub; , U7 }# U" N; P# v1 I. B! f 0 d: i8 ^( c% c2 q Cal* p_cal = new Cal();& n: a0 o, s) e w
int r1 = (p_cal->*fun)(2, 3);7 d& ?9 ^7 n' |! k) d
delete p_cal; z3 X+ C! t- e0 v, ` 4 o0 t# s, D4 [3 v7 p Cal local_cal; + z$ Y7 E7 W2 ^0 E4 V int r2 = (local_cal.*fun)(8, 6);* @# |- {' A0 t! P; ^
} u; X* x/ v; f, u! {0 |( f5 b M. C7 G" T
成员变量指针 7 r% u6 P! G7 ^+ B, i成员变量指针比成员函数指针还要简单些,没有函数调用, 无需考虑函数调用和间接引用符*的优先级问题。 6 w! z9 u4 M1 M% ^5 V$ o 4 N, j4 `- g6 F- O4 `成员变量指针的定义 % S; S' ^* P& y8 O2 f, {( m假如以下结构体C。* P- c8 p, J3 G; t5 E* l& s7 u