引言
pointer,有时候还是会很让人困扰。简单的还好,int * pt; 复杂一点,int ** pt; 还有什么 void * pt;
本文稍微总结一下,指向不同类型的变量或函数的指针。
如,指向int型变量的,指向int*的,指向char的,char*的,指向void型的,
int * 型数组,char * 型数组,
指向普通函数的,指向成员变量的,指向成员函数的指针…
指向int型的指针
这个不用多说。
int i = 3;
int * p1 = &i;
int * p2;
p2 = &i;
注意。
1. *在声明时出现和后面使用的时候是有区别的。声明时,是说这是个指针;以后使用时,是解引用dereference。
2. &在声明时出现和后面使用的时候,也有区别。声明时,是说这是某个东西的引用;以后使用时,是去取这个东西的地址。
3. i有一个地址,存在了p1和p2里,p1和p2的值即为i的地址。
4. *p1和*p2是解引用,相当于i。可以输出*p1,是3,也可以通过*p1修改i的值。
5. p1和p2本身都有地址,即&p1和&p2。
另外,int * iArray是可以指向一个int型数组的。
int iArray[3] = {1,2,3};
int * pt = iArray;
*(pt + 2) = 0; // 相当于 iArray[2] = 0;
*(pt+3) = 0; // 越界
指向int*型的指针
两重指针,两颗星。
int i = 3;
int * p1 = &i;
int ** p2 = &p1;
数清楚几颗星就好。
另外, int ** iMat 可以指向一个二维数组。确切地说,是指向一个int *型数组。
int*型数组
int iArray1[4] = {1,2,3,4};
int iArray2[3] = {1,2,3};
int iArray3[5] = {1,2,3,4,5};
int * iMat[3] = {iArray1,iArray2,iArray3};
可以用int*型数组创建一个矩阵。也可以用int ** 创建一个矩阵。
指向char型的指针
char后面跟着一个星星。可以指向一个char型变量。
char ch = 'a';
char * pt1 = &ch;
*pt1就是ch了。输出是'a',也可以修改ch的值,e.g. *pt1 = 'c';
另外i,char * pt可以指向一个C语言风格的字符串。(一个char型数组,末尾有'\0')
char * pt2 = "abcd";
char*型数组
char * cPtArray[3] = {"I","love","music"};
for (int i = 0;i<3;i++)
{
cout<<cPtArray[i]<<endl;
}
屏幕上将输出
I
love
music
指向char*型的指针
两个星星。可以指向一个字符串数组。
char * pt3[3] = {"abc","fudan","university"};
char ** pt4 = pt3;
for (int i = 0;i<3;i++)
{
cout<<pt4[i]<<endl;
}
屏幕上将输出:
abc
fudan
university
fudan
university
指向void型的指针
int i = 3;
double d = 4.5;
void * pt;
pt = &i; // 先指向一个int型变量
// cout<<*pt<<endl; // 报错!不能直接解引用!
cout<<*(int*)pt<<endl; // 要先强制转型成指向某种类型的指针,才能解引用。
pt = &d; // 再指向一个double型变量
cout<<*(double*)pt<<endl;
cout<<*static_cast<double*>(pt)<<endl;
屏幕上将输出:
3
4.5
4.5
4.5
4.5
指向普通函数的指针
在C++中,普通函数的函数名是函数地址。
为什么会有函数指针呢?
以下内容摘自百度百科。
函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是大体一致的。函数指针有两个用途:调用函数和做函数的参数。
就我目前的知识储备而言,在windows程序设计,装载完动态链接库(DLL)以后,调用DLL里的函数,函数指针似乎就看出函数指针的作用了。(调用函数)
A function block also occupies memory space–placed at Code Section
–has its own address
指向普通函数的指针,写法是这样的。
函数返回数据的数据类型 (指针名*) (形参列表);
rtn_type (*pFun)(para_list);
e.g. 一个指向
int fun1(int a, char * c);
的函数指针,在声明的时候,要这样写
int (*fp1) (int a, char * c);
注意:
1. 返回值要对上;
2. *和fp1要用括号括起来;
3. 形参数据类型要一模一样,一一对应;(假设函数调用的时候,参数进栈方式相同)
给fp1赋值的时候,要这样写
fp1 = fun1;
// 或 fp1 = &fun1;
两种写法,对于指向普通的函数的函数指针来说,都是可以的。
在通过函数指针调用函数的时候,要这样写成这种形式
fp1(3,"China");
// 或 (*fp1) (3,"China");
指向成员变量的指针
指向成员变量的指针,和指向普通的变量的指针,最大的不同之处就在于,指针类型不同。
指向成员变量的指针,在声明的时候,一定要加上类的界定符号!在定义或在赋值,
对该指针即将指向的那个成员变量取地址的时候,也要在&的后面加上类的界定符号!
datatype (CName::* pName);
pName = &CName::data_member;
pName = &CName::data_member;
比如,有个CA类。
class CA {
public:
int i;
}
指向A中的i的指针,要写为
int CA :: * pt1 = & CA :: i;
好诡异的写法。这是规定。注意,这里的int i还是public修饰的,不然后面点不出来啊…
在解引用的时候,也要通过某个obj一点把它点出来再解引用。
CA obj;
obj.*pt1 = 3; //相当于是 obj.i = 3;
指向成员函数的指针
和指向成员变量的指针类似,在声明、定义或引用的时候,都要加上类的界定符号!
class CA {
public:
int fun1( int x, int y, char c);
}
那指向CA中fun1的函数指针要这么声明
int ( CA :: * fp1) (int x, int y, char c);
赋值则要这么写
fp1 = & CA::fun1;
注意,这里一定要有取地址的符号!一定要有&符号!!
使用fp1,则要通过某个obj.出来
CA obj;
obj.*fp1(3,4,'a');
一点“.”,给人看起来就像是obj的成员,
还要取*,因为是指向函数的指针,要使用这个函数,需要解引用。
member functions are not put at the space of objects but that all class objects share.
member functions are not put at the space of objects but that all class objects share.
尽管某个class的成员函数是该类的所有的obj实例都享有,但是调用class里的成员函数,
除了public修饰外,没有更多的修饰字,现在看起来,似乎,都只能通过具体的对象来获得。
不能通过某个class的类名,直接取出来用。(static修饰的函数,是可以的…)
至于更多详细的关于class的内容,包括this指针、static修饰字等更多细节的内容,我会在以后的文章中总结。
谢谢观赏!