首先需要清楚数组名是数组首元素的地址,不管是一维还是多维,它是个常量,而指针是个可以存储地址的变量。使用时可以将数组名看成一个常量指针。 C/C++中没有内置的多维数组,多维数组是数组的数组。例如二维数组就是元素为一维数组的一维数组,此时数组名依然是数组的第一个元素的地址。 具体解释看代码注释及代码的运行结果。 C/C++中的函数无法返回数组,所以在使用函数操作数组时,只能通过指针或者结构体等方式来间接返回数组,当然可以返回数组名,因为数组是个地址,相当于一个常量指针。具体详解可以看SOF: Return a 2d array from a function
以下代码为了方便查看和分析,所以只是代码片段
一维数组与指针 1 2 3 4 5 6 int ar[20 ] = {1 ,2 ,3 }; int *p1 = ar; int (*p2)[20 ] = &ar; std::cout << "p1+1: " << p1+1 << "\tar+1: " << ar+1 << "\t&ar[1]: " << &ar[1 ] << std::endl; std::cout << "*(p1+1): " << *(p1+1 ) << "\t*(ar+1): " << *(ar+1 ) << std::endl; std::cout << "*p2: " << *p2 << "\tp1: " << p1 << "\t**p2: " << **p2 << "\t*p1: " << *p1 << std::endl;
p1是一个指向int型变量的指针,p1存储的地址与ar是一样的,都是数组第一个元素的地址,但p1是指针变量,ar是个常量地址,p1++等价于p1=p1+1, 但不能使用ar++。下标的操作在C++中会转化为对地址的操作,如ar[i]会被转化为(ar + i), p2是一个指针,不同于int *p2[20];不加小括号时,p2会优先与后面的[20]结合,导致p2成为指针数组, 即含有20个int型指针的数组。而加了小括号p2先与 结合,p2成为指针,该指针指向一个含有20个int 型元素的数组,恰好与ar数组类型相同。注意ar是一个数组,数组名表示的是该数组的第一个元素的地址。 例外情况是对数组名使用sizeof运算符将获得整个数组的大小(单位是字节)。 而对数组名取地址时,得到的将是该连续20个地址空间的首地址,虽然值相同,但意义不同。 &ar[0]/p1/ar表示的是一个4字节的内存块的首地址,而&ar却表示204个字节的内存块首地址。 相当于此时对p1/ar加1时增加的最小单位是4个字节的连续内存空间,也就是对应第二个元素,而对&ar/p2加1是毫无意义的,增加是20 4个字节的连续内存空间,将会越界, 可对其解引用一次得到数组第一个元素的地址,即*p2等价于p1。
二维数组与指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 std::cout << "**********二维数组与指针*********" << std::endl; int arr[5 ][6 ] = {{1 ,2 ,3 }}; int (*pp1)[6 ] = arr; int (*pp2)[5 ][6 ] = &arr; std::cout << "&arr[0][0]: " << &arr[0 ][0 ] << "\tarr: " << &arr << "\tpp1: " << pp1 << "\t*pp2: " << *pp2 << "\t**arr: " << **arr << std::endl; for (int (*pr)[6 ] = arr; pr != arr + 5 ; ++pr) { for (int *pc = *pr; pc != *pr + 6 ; ++pc) std::cout << *pc << " " ; std::cout << std::endl; }
二维数组arr[i][j]会被解析成( (arr + i) + j),arr依然是第一个元素的地址, 此处的第一个元素即可以表示arr[0][0](即二维数组的第一个元素),也可以表示以行为元素的一维数组的 第一个元素(arr + 0)(即第一行的6个元素),显然这两个地址是相同的。所以对arr增加1,即移到下一个 元素的地址,下一个元素即第二行。arr的元素是含有6个int的一维数组,所以指向arr的指针类型也必须是含有 6个int的一维数组,所以 pp1的括号和后面的[6]必须要有。 pp2的解释与p2类似
函数和数组 首先明确C/C++中函数无法返回数组,所以对数组的操作和返回只能通过指针,而数组名本身就是个地址,可以看成是个常量指针 以下两种方式定义一个返回二维数组的函数,实际上返回的依然是指针
1 2 3 4 5 6 7 8 typedef int (*Tarr) [6] ;Tarr func (int (*arr)[6 ]) { return arr; }
上述声明等价于
1 2 3 4 5 6 7 8 int (*func (int (*arr)[6 ]))[6 ]{ return 0 ; } int c[5 ][6 ];Tarr b = func (c); std::cout << "&b[1][1]: " << &b[1 ][1 ] << "\t&c[1][1]: " << &c[1 ][1 ] << std::endl;
函数和指针 这里的介绍非常详细http://www.cnblogs.com/TenosDoIt/p/3164081.html C语言函数指针的定义形式:返回类型 (*函数指针名称)(参数类型1, 参数类型2, 参数类型3, ...);
C++语言函数指针的定义形式:返回类型 (类名称::*函数指针名称)(参数类型1, 参数类型2, 参数类型3, ...);
注意,当定义指向类的成员函数的函数指针时,该成员函数如果不是静态成员函数,也必须通过类对象来调用。不能定义指向一个类对象的函数的函数指针。 与C++类相关的函数指针的定义都需要使用作用域运算符::
,赋值都要带取地址符&
,通过类对象访问需要使用.*
,通过类对象指针调用成员函数指针需要使->*
普通函数指针和类成员函数指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> void tf (char c, int i) { std::cout << "Normal: " << c << i << std::endl; } class A {public : void func1 (char c, int i) { std::cout << "Class func1: " << c << i << std::endl; } void func2 (char c, int i) { std::cout << "Class func2: " << c << i << std::endl; } static void func3 (char c, int i) { std::cout << "Class func2: " << c << i << std::endl; } void func4 (char c, int i) const { std::cout << "Class func2: " << c << i << std::endl; } }; int main (void ) { void (*pf)(char , int ) = NULL ; pf = tf; pf ('t' , 1 ); void (A::*pf1)(char , int ) = &A::func1; A obj_a; (obj_a.*pf1)('f' , 1 ); A obj_b; pf1 = &A::func2; (obj_b.*pf1)('f' , 1 ); pf = A::func3; pf ('f' , 3 ); void (A::*pfc)(char , int ) const = &A::func4; A obj_c; (obj_c.*pfc)('c' , 4 ); return 0 ; }
输出结果:
1 2 3 4 5 Normal: t1 Class func1: f1 Class func2: f1 Class func2: f3 Class func2: c4
函数指针作为参数和返回值 要善用typedef简化函数指针类型的定义。具体看下面的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> int display (char c, int i) { for (int n = 0 ; n < i; ++n) std::cout << c; std::cout << std::endl; return i; } void dfun (int (*pp)(char , int ), char c, int i) { pp (c, i); } int (*pdfun (int (*pd)(char , int ), char c, int i))(char , int ){ pd (c, i); return pd; } int main (void ) { dfun (display, 'd' , 6 ); int (*pd)(char , int ) = pdfun (display, 'p' , 7 ); pd ('p' , 8 ); typedef int (*pd_type) (char , int ) ; pd_type pdd = display; pdd ('s' , 10 ); typedef int (*(*pdfun_type)(pd_type, char , int )) (char , int ) ; pdfun_type ppdfun = pdfun; pd_type ppd = ppdfun (pdd, 'u' , 12 ); ppd ('x' , 15 ); return 0 ; }
输出:
1 2 3 4 5 6 dddddd ppppppp pppppppp ssssssssss uuuuuuuuuuuu xxxxxxxxxxxxxxx
函数指针数组 举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> float f1 (float a, int b) { std::cout << a << " + " << b << " = " << a + b << std::endl; return a + b; } float f2 (float a, int b) { std::cout << a << " * " << b << " = " << a * b << std::endl; return a * b; } int main (void ) { float (*pfa[2 ])(float , int ) = {f1, f2}; for (int i = 0 ; i < 2 ; ++i) { pfa[i](3 , 9 ); } typedef float (*f_type) (float , int ) ; f_type pfa2[] = {f1, f2}; for (int i = 0 ; i < 2 ; ++i) { pfa2[i](6 , 8 ); } return 0 ; }
输出为:
1 2 3 4 3 + 9 = 12 3 * 9 = 27 6 + 8 = 14 6 * 8 = 48