函数指针+回调函数+点云鼠标点选和框选

C++函数指针

如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。

获取函数指针:函数的地址就是函数名,要将函数作为参数进行传递,必须传递函数名。

声明指针时,必须指定指针指向的数据类型,同样,声明指向函数的指针时,必须指定指针指向的函数类型,这意味着声明应当指定函数的返回类型以及函数的参数列表。

函数指针作为参数进行传递时:

void call(int(*callback)(int),int a)  //函数指针作为参数传递的正确写法
void call(int *(callback)(int),int a) //这不是函数指针的声明,这种写法本质上是声明了一个函数叫做callback,其返回值是int数据类型的指针,就是所谓的指针函数。

使用函数指针调用函数:

#include <iostream>

int add(int a, int b)
{
    
    

	return a + b;
}

void call(int (*callback)(int ,int ),int a ,int b)
{
    
    

	std::cout << a << " b: " << b << std::endl;
	std::cout << callback(a, b) << std::endl;
}

int main()
{
    
    

	int a = 10;
	int b = 20;
	call(add, a, b);      //函数指针作为参数传递

	int (*p)(int, int);   //声明一个函数指针
	p = add;              //使用指针调用函数,函数名就是函数地址
	std::cout << (*p)(a, b) << std::endl;  //结果是30

	return 0;
}

例程2:

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;
double* f4(double[], int n);    //声明一个函数,返回值是double数据类型的指针

int main(int argc, char* argv[])
{
    
    
	double a[3] = {
    
     12.1, 3.4, 4.5 };

	double* (*p)(double[], int n) = f4;   //声明函数指针,指向f4
	cout << *p(a, 0) << endl; 
	cout << *(*p)(a, 0) << endl;
	cout << (*p)(a, 0) << endl;
	return 0;
}

double* f4(double arr[], int n)
{
    
    
	return arr + n;
}

输出结果:
在这里插入图片描述
这说明p(a, 0)等价于(*p)(a,0)

指针函数:int* fun(int x,int y);
指针函数本质是一个函数,其返回值为指针。

函数指针:int (*fun)(int x,int y);
函数指针本质是一个指针,其指向一个函数。

再次梳理

int func(int* a, int b)这是一个函数func,参数列表是(int* a,int b),返回值是int数据类型。那么,这个指向这个函数的函数指针可以写成int (*p)(int *a,int b)。调用这个函数指针可以写成(*p)(&a,b),此时返回的是int类型,按道理可以进一步写成int c = (*p)(&a,b)。

如果返回的不是一个int类型的数据,而是一个函数指针。假如一个函数是func,其参数列表为(int)类型,其返回值是函数指针int (p)(int a,int b)。
使用别名,将PF定义成指向函数类型的指针。

using PF = int (*)(int* a,int b);

那么func的声明就可以写成

PF func(int c);

func需要return一个函数指针,所以先定义这个函数指针。

int f1(int* a, int b)
{
    
    
	std::cout << "a: " << &a << " b: " << b << std::endl;
	return b;
}
int (*p)(int *a,int b) = f1; //定义函数指针指向函数f1

此时,就可以写出func的定义:

PF func(int c)
{
    
    
	std::cout << "c:" << c << std::endl;
	return *p;  //返回函数指针
}

于是在main函数中可以写成:

int main()
{
    
    	
	int c = 10;
	int d = 12
	int e = 13;
	func(c); //输出 c: 10  其实由于func返回的是一个函数指针,而函数指针可以直接(*p)(&a,b)来实现调用。
	int (*p2)(int *,int) = func(c);
	//下列两个等价
	p2(&d,e);
	func(c)(&d,e);

	return 0;
}

数组指针

如果一个数组中的元素有几千个,则一个个的声明指针并赋值显得非常的麻烦和不方便
而数组指针是一种专门用于数组的一种指针。 指针指向一个数组的首地址。

定义数组指针变量:
语法:数据类型 (*数组指针变量名)[元素量];

将数组的地址储存到数组指针变量中:
语法:数组指针变量名 = &数组;

double a[3] = {
    
    1.2, 1.3, 1.4};
double*p[3] = a;     //error 错误 这是指针数组的声明方式
double (*p)[3] = a;  //error 错误 a是数组的首个元素首地址
double (*p)[4] = &a; //error 错误 数组指针和数组的长度不相等
double(*p)[3] = &a;  //正确       &a是数组首地址

数组指针的长度必须与指向的数组的长度保持一致。

指针数组

指针的数组可以理解为“指针的数组”,即数组中所有元素都是指针类型的。
语法:数据类型* 指针组名[元素量];

int var[3] = {
    
     10,100,1000 };
const int* p[3];
for (int i = 0; i < 3; i++)
{
    
    
	p[i] = &var[i];
}

for (int j = 0; j < 3; j++)
{
    
    
	cout << p[j] << "  " << *p[j] << endl;
}

const char* p2[3] = {
    
    
	"hello",
	"great",
	"world"
};

for (int k = 0; k < 3; k++)
{
    
    
	cout << p2[k] << "   " << *p2[k] << endl;
}

char str0[10] = {
    
     'Z','a','r','a',' ','A','l','i' };
cout << str0 << endl;

输出结果:
在这里插入图片描述
参考:C++指针数组

函数的形参用void*,表示接受任意数据类型的指针。
1.不能用void声明变量,它不能代表一个真实的变量;
2.不能对void* 指针直接解引用(需要转换成其他类型的指针);
3.把其他类型的指针赋值给void* 指针不需要转换;
4.把void*指针赋值给其他类型的指针需要转换。

指针类型转换例程

int a = 10;
int* p = &a;
float b = 1.1;
float* p2 = &b;
cout << "p: " << p << endl;
cout << "*p: " << *p << endl;
cout << "p2: " << p2 << endl;
cout << "*p2: " << *p2 << endl;
p = (int*)p2;
cout << "p: " << p << endl;
cout << "*p: " << *p << endl;
cout << "p2: " << p2 << endl;
cout << "*p2: " << *p2 << endl;

结果如下:
在这里插入图片描述
p和p2都指向了同一个地址,但是解引用出来的结果不一样。这篇博客给出了一些解释——C/C++强制类型转换、指针类型转换发生了什么。

指针越界

防止指针越界的方法
1.必须让指针指向一个有效的内存地址;
2.防止数组越界;
3.防止向一块内存中拷贝过多的内容;
4.防止使用空指针;
5.防止改变const修改的指针;
6.防止改变指向静态存储区的内容;
7.防止两次释放同一个指针;
8.防止使用野指针。

全局变量和局部变量在内存中的区别

全局变量储存在静态数据库,局部变量在堆栈。

Heap和stack的差别

Heap是堆,stack是栈;
stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放;
stack空间不足够大且有限,heap是很大的自由储存区;
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行。

猜你喜欢

转载自blog.csdn.net/dyk4ever/article/details/126832556