【019】C++ 中的强大组合:指针与函数

引言


💡 作者简介:专注分享高性能服务器后台开发技术知识,涵盖多个领域,包括C/C++、Linux、网络协议、设计模式、中间件、云原生、数据库、分布式架构等。目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。公众号《Lion 莱恩呀》。
👉
🎖️ CSDN实力新星、专家博主,阿里云博客专家、华为云云享专家
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【018】C++的指针数组和数组指针
🔔 下一篇:【020】C++的动态内存申请new和delete

一、指针变量作为函数的参数

如果想在函数内部修改外部变量的值,需要将外部变量的地址传递给函数。

1.1、单向传递:值传递

函数内部不能修改外部变量的值。

#include <iostream>
using namespace std;

void set(int num2)// 相当于 int num2=num;
{
	num2=10;
}
int main()
{
	int num=1;
	set(num);
	cout<<"num = "<<num<<endl;
	return 0;
}

输出:

num = 1

1.2、单向传递:传地址

函数内部可以修改外部变量的值。

#include <iostream>
using namespace std;

void set(int *p)// 相当于 int *p=&num;
{
	*p=10;
}
int main()
{
	int num=1;
	set(num);
	cout<<"num = "<<num<<endl;
	return 0;
}

输出:

num = 10

二、数组作为函数的参数传递

函数内部想操作外部数组元素,将数组名传递给函数。

  • 一维数组作为函数的参数,会被编译器优化为指针变量。
  • 二维数组作为函数的形参会被优化成一维数组指针。

(1)一维数组作为函数的参数传递:

#include <iostream>
using namespace std;

void foreach(int p[5])//优化成void foreach(int *arr)
{
	cout<<"sizeof(p) = "<<sizeof(p)<<endl;
	//遍历
	for(int i=0;i<5;i++)
	{
		cout<<p[i]<<" ";
	}
	cout<<endl;
}
int main()
{
	int num[5]={1,2,3,4,5};
	cout<<"sizeof(num) = "<<sizeof(num)<<endl;
	foreach(num);
	
	return 0;
}

输出:

sizeof(num) = 20
sizeof(p) = 4
1 2 3 4 5

(2)二维数组作为函数的参数传递:

#include <iostream>
using namespace std;
// void foreach(int (*p)[4],int row,int col)和下面的等价
void foreach(int p[3][4],int row,int col)
{
	cout<<"sizeof(p) = "<<sizeof(p)<<endl;
	//遍历
	for(int i=0;i<col;i++)
	{
		for(int j=0;j<col;j++)
			cout<<p[i][j]<<" ";
		cout<<endl;
	}
	cout<<endl;
}
int main()
{
	int num[3][4]={
		{1,2,3,4},
		{5,6,7,8},
		{9,10,11,12}
	};
	cout<<"sizeof(num) = "<<sizeof(num)<<endl;
	foreach(num,sizeof(num)/sizeof(num[0]),sizeof(num[0])/sizeof(num[0][0]));
	
	return 0;
}

输出:

sizeof(num) = 48
sizeof(p) = 4
1 2 3 4 
5 6 7 8
9 10 11 12

三、函数的返回值类型是指针类型

将函数内部的合法地址通过返回值返回给函数外部使用。

注意:函数不要返回普通局部变量的地址,返回普通局部变量的地址会出现段错误,使用一个已经释放的内存空间的行为是未定义的。但是,可以返回静态变量的地址,因为静态变量的生命周期是整个进程,所以是一个合法的地址。

#include <iostream>
using namespace std;
int* test()
{
	// int data=1;
	// return &data;
	static data=2;
	return &data;
}
int main()
{
	int *p=test();
	cout<<"test return "<<*p<<endl;// 输出2
	return 0;
}

四、函数指针

4.1、函数指针的定义

函数名代表函数的入口地址。函数指针本质上是一个指针变量,只是该变量保存的是函数的入口地址。

#include <iostream>
using namespace std;
int add(int x, int y)
{
	return x+y;
}
int main()
{
	// 函数指针
	int (*p)(int,int)=NULL;
	cout<<"sizeof(p) = "<<sizeof(p)<<endl;// 输出4
	// 函数指针与函数入口建立关系
	p=add;
	// 通过函数指针调用函数
	cout<<p(1,2)<<endl;//输出3
	return 0;
}

4.2、函数指针变量的注意事项

  1. 函数指针变量不要加1操作,没有意义。
  2. 不要对函数指针变量取*,没有意义,编译器会自动优化。
  3. 函数指针变量判断大小也没有意义。
  4. 函数指针变量可以赋值,比如:p1=p2。
  5. 函数指针变量可以判断相等,比如:p1==P2。

4.3、函数指针变量使用typedef定义别名

#include <iostream>
using namespace std;
int add(int x, int y)
{
	return x+y;
}
typedef int (*FUNC_NAME)(int,int);
int main()
{
	// 函数指针
	FUNC_NAME p =NULL;
	cout<<"sizeof(p) = "<<sizeof(p)<<endl;// 输出4
	// 函数指针与函数入口建立关系
	p=add;
	// 通过函数指针调用函数
	cout<<p(1,2)<<endl;//输出3
	return 0;
}

4.4、函数指针作为函数的参数

目的:让算法功能多样化,更加强大。

#include <iostream>
using namespace std;
int add(int x, int y)
{
	return x+y;
}
int sub(int x, int y)
{
	return x-y;
}
int mul(int x, int y)
{
	return x*y;
}
int div(int x, int y)
{
	return x/y;
}
int myCalc(int x,int y,int (*func)(int,int))
{
	return func(x,y);
}
int main()
{
	cout<<myCalc(20,30,add)<<endl;
	cout<<myCalc(20,30,sub)<<endl;
	cout<<myCalc(20,30,mul)<<endl;
	cout<<myCalc(20,30,div)<<endl;
	return 0;
}

五、总结

C++中指针和函数有着紧密的联系,指针可以用来存储函数的地址,通过指针调用函数或者将函数作为参数传递给其他函数。

  1. 如何定义一个函数指针?定义一个函数指针需要声明一个与被调用函数相同返回类型和参数列表的指针类型,例如:

    int (*func_ptr)(int, int); // 定义了一个接受两个整型参数并返回整型结果的函数指针
    
  2. 如何将函数地址赋值给指针?可以使用取地址符号&获取函数地址,并将其赋值给对应类型的指针变量,例如:

    int add(int a, int b) { return a + b; }
    int (*func_ptr)(int, int) = &add; // 将add()的地址赋值给func_ptr
    
  3. 如何通过函数指针调用对应的函数?可以使用解引用运算符*或者直接使用函数名加括号() 进行调用,例如:

    int result = (*func_ptr)(1, 2); // 使用解引用运算符进行调用
    int result2 = func_ptr(1, 2);    // 直接使用函数名进行调用(会隐式地转换成解引用)
    
  4. 如何在其他函数中传递一个包含参数为函数指针的形参?可以将该形参声明为一个带有函数指针类型参数的函数,例如:

    void operate(int a, int b, int (*func_ptr)(int, int)) { 
        // func_ptr 接收两个整型参数并返回整型结果的函数指针
        int result = func_ptr(a, b);
        cout << "The result is: " << result << endl;
    }
    
    int add(int a, int b) { return a + b; }
    operate(1, 2, &add); // 调用 operate() 函数,并将 add() 函数地址传递给 func_ptr 形参
    
  5. 如何使用typedef为函数指针类型定义别名?可以使用typedef为复杂的函数指针类型定义别名,简化代码,例如:

    // 定义一个 CalcFuncPtr 类型为接受两个整数并返回整数的函数指针
    typedef int (*CalcFuncPtr)(int, int); 
    
    int add(int a, int b) { return a + b; }
    CalcFuncPtr func_ptr = &add;   // 使用别名定义一个 CalcFuncPtr 类型的变量
    int result = func_ptr(1, 2);   // 直接调用该变量即可
    

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion Long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值