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


    C++函数指针

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

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

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

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

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

    使用函数指针调用函数:

    #include 
    
    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;
    }
    
    • 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

    例程2:

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    输出结果:
    在这里插入图片描述
    这说明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);
    
    • 1

    那么func的声明就可以写成

    PF func(int c);
    
    • 1

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

    于是在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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    数组指针

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

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

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

    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是数组首地址
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    指针数组

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

    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;
    
    • 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

    输出结果:
    在这里插入图片描述
    参考: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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    指针越界

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

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

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

    Heap和stack的差别

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

  • 相关阅读:
    掌握未来技术:一站式深度学习学习平台体验!
    移动端测试
    宽字节注入
    C++语言中预处理指令
    求职简历这样写,轻松搞定面试官
    MacM1 AndroidStudio 自带模拟器安装不上apk
    超适合练手的一套JavaWeb项目 (保安管理系统)
    次时代武器全流程大揭秘
    高校校企合作平台设计与实现-计算机毕业设计源码+LW文档
    Oracle监听连接速度很慢且不稳定问题排查与解决
  • 原文地址:https://blog.csdn.net/dyk4ever/article/details/126832556