指针型函数参数
将一个函数的参数声明成引用还是指针,这两种参数都允许函数修改实参指向的对象,两种类型的参数都允许有效地向函数传递大型类对象,但是这两种参数有着区别。
引用必须被初始化为指向一个对象,一旦初始化了,它就不能再指向其他对象,指针可以指向一系列不同的对象也可以什么都不指向。
void manip( X *px )
{
// 在解引用指针之前确信它非 0
if ( px != 0 )
// 解引用指针
}
如果一个参数可能在函数中指向不同的对象,或者这个参数可能不指向任何对象,则必 须使用指针参数。
new出来的内存是放在堆里面,不会随着函数的结束而释放,但是函数内的指针变量pi是一个临时变量,会随着函数的结束而消亡。
void createMemory(int *pi,int size)
{
cout<<&pi<<endl;
pi = new int[size];
}
void main()
{
int *pi = NULL;
createMemory(pi,100);
cout<<&pi<<endl;
system(“pause”);
}
指针作为参数并且在函数内部创建内存,则应该使用二级指针作为参数,原因是二级指针保存的是实参指针的内存地址。
void createMemory(int **pi,int size)
{
cout<<pi<<endl;
*pi = new int[size];
}
void main()
{
int *pi = NULL;
createMemory(&pi,100);
cout<<&pi<<endl;
system(“pause”);
}
函数指针
一个函数在编译时被分配一个入口地址。这个入口地址就称为函数指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。
返回值的数据类型 (*指针变量名)(函数参数列表)
指向函数的指针在调用所指向的函数时,无需解引用,直接使用指针名代替函数名。
函数指针的数组,可以用来保存符合返回值和参数的一系列函数的内存地址。
函数返回值数据类型 (*指针名[数组大小]) (参数类型表)
指针函数
编译以下代码,查看输出结果,可以看到输出的三个值都不同,局部变量ival有自己的内存地址,函数有自己的内存地址,函数的返回值又是一个内存地址。
{
cout<<ival<<endl;
return &ival;
}
void main()
{
int ival = 10;
int* (*pf)(int) = printNumber;
cout<<printNumber(10)<<endl;
cout<<&ival<<endl;
cout<<pf<<endl;
system(“pause”);
}
使用指针函数的时候需要注意,避免返回局部变量或临时变量的地址。
避免返回局部变量或临时变量的地址的原因是,局部变量或者临时变量的内存释放后,导致当前指针指向无效的内存地址,所以使用指针函数时要注意返回的指针是否有效。以下代码,函数返回了无效的内存地址。
char* copyString()
{
char str[100]={};
return str;
}
void main()
{
char str[50] = "helloWorld";
char* pc = copyString();
strcpy(pc,str);
cout<<pc<<endl;
system(“pause”);
}
实现一个按钮注册系统
编写一个注册函数RegistButton用于注册按钮
编写一个NotifyClick函数用来模拟系统触发某个按钮的事件
void OnBtnStart()
{
cout << "开始游戏" << endl;
}
void OnBtnPause()
{
cout << "暂停游戏" << endl;
}
int RegistButton(void(*pLisents[10])(), void(*pF)())
{
static int index = 0;
pLisents[index++] = pF;
return index - 1;
}
void NotifyClik(void(*pLisents[10])(),int iD)
{
pLisents[iD]();
}
void main()
{
void(*pListeners[10])();
int startID = RegistButton(pListeners, OnBtnStart);
int pauseID = RegistButton(pListeners, OnBtnPause);
NotifyClik(pListeners, 0);
NotifyClik(pListeners, 1);
}