【019】C++的指针与函数

news2024/11/27 16:28:17

C++的指针与函数

  • 引言
  • 一、指针变量作为函数的参数
    • 1.1、单向传递:值传递
    • 1.2、单向传递:传地址
  • 二、数组作为函数的参数传递
  • 三、函数的返回值类型是指针类型
  • 四、函数指针
    • 4.1、函数指针的定义
    • 4.2、函数指针变量的注意事项
    • 4.3、函数指针变量使用typedef定义别名
    • 4.4、函数指针作为函数的参数
  • 总结

引言


💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
👉
🎖️ CSDN实力新星,社区专家博主
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【018】C++的指针数组和数组指针

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

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

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); // 定义了一个接受两个整型参数并返回整型结果的函数指针
  1. 如何将函数地址赋值给指针?

可以使用取地址符号&获取函数地址,并将其赋值给对应类型的指针变量,例如:

int add(int a, int b) { return a + b; }
int (*func_ptr)(int, int) = &add; // 将add()的地址赋值给func_ptr
  1. 如何通过函数指针调用对应的函数?

可以使用解引用运算符*或者直接使用函数名加括号() 进行调用,例如:

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

可以将该形参声明为一个带有函数指针类型参数的函数,例如:

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 形参
  1. 如何使用typedef为函数指针类型定义别名?

可以使用typedef为复杂的函数指针类型定义别名,简化代码,例如:

typedef int (*CalcFuncPtr)(int, int); // 定义一个 CalcFuncPtr 类型为接受两个整数并返回整数的函数指针

int add(int a, int b) { return a + b; }
CalcFuncPtr func_ptr = &add;   // 使用别名定义一个 CalcFuncPtr 类型的变量
int result = func_ptr(1, 2);   // 直接调用该变量即可

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/607854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rabbitmq死信队列详解

目录 1 概念 2 成为死信队列的条件 2.1 队列指定长度 2.2 消息ttl时间 2.3 消费者拒收消息 1 概念 死信队列&#xff1a;死信队列其实和普通的队列一样&#xff0c;只不过里面存放的消息都是普通队列过期没有消费的。所以&#xff0c;接收没有及时被消费消息的队列为死信…

[SWPUCTF 2021 新生赛] (WEB二)

目录 easyupload1.0 easyupload2.0 easyupload3.0 no_wakeup PseudoProtocols error hardrce pop sql finalrce hardrce_3 easyupload1.0 1.启动环境 2.上传一个图片木马 GIF89a <script languagephp>eval($_POST[a]);</script>3.蚁剑连接&#xff0c;…

VBScript深度学习入门——线性回归

背景 破电脑装不了VS、Py、IDea、Golang等主流编译器或其语言运行环境&#xff0c;但是自带.Net FrameWork 3.5&#xff0c;可以使用VBScript进行脚本编写&#xff0c;无所谓&#xff0c;反正都是了解底层原理学习&#xff0c;大不了手搓机器学习框架。 分析 了解线性回归的…

剑指 Offer 24. 反转链表解题思路

文章目录 题目解题思路 题目 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 限制&#xff1a; 0 < 节点个数 < 5000 …

去过门头沟吗?

门头沟&#xff08;Mt.Gox&#xff09; 1. 成立2. 发展3. 危机4. 后续 1. 成立 MtGox是程序员杰德麦凯莱布&#xff08;Jed MeCaleb&#xff09;在比特币论坛的用户名。2007年&#xff0c;麦凯莱布开发了魔法风云会线上交易平台&#xff1a;门头沟&#xff08;Mt.Gox&#xff…

【数据分析之道-Matplotlib(六)】Matplotlib饼图

文章目录 专栏导读1、Matplotlib饼图pie()语法格式2、设置饼图各个扇形的标签与颜色3、突出显示第二个扇形&#xff0c;并格式化输出百分比4、shadows通过将参数设置为&#xff1a;向饼图添加阴影 True5、使用legend()函数为每个楔形添加解释列表6、将title参数添加到legend 函…

MYSQL实战45讲笔记--基础架构:一条SQL查询语句是如何执行的?

基础架构&#xff1a;一条SQL查询语句是如何执行的&#xff1f; **select** * **from** T **where** ID10mysql架构 MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层&#xff1a;连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务…

不同平均值—集合—力扣—Python

一、题目描述&#xff1a; 二、代码解题&#xff1a; 1.不含注释语句的 class Solution:def distinctAverages(self, nums: List[int]) -> int:avg set([])l len(nums)//2for i in range(0,l):mi min(nums)ma max(nums)p (mima)/2avg.add(p)nums.remove(mi)nums.remo…

Python-For-EEG基础代码讲解(1)

Python-For-EEG 我要演示脑电图信号的基本分析。 主题 1、基于时域分析&#xff0c;P300信号数据集 Event-related potentials and 1-dimensional convolution&#xff08;ERP,CNN&#xff09;Long short-term memory(LSTM) 2、基于频域分析&#xff0c;DEAP和SSVEP数据集…

LeetCode_双指针_中等_82.删除排序链表中的重复元素 II

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回已排序的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&…

oracle19c SYSAUX表空间使用率高

今早手机收到一个信息&#xff0c;某客户的19c环境sysaux使用率超过了80%告警了。既然有事了还是需要登录查看下的 SYS > SET LINES 120 pagesize 199; SYS > COL OCCUPANT_NAME FORMAT A30; SYS > SELECT * FROM (SELECT OCCUPANT_NAME,SPACE_USAGE_KBYTES FROM V$S…

【逆向基础】JS逆向入门:小白也可以看懂

文章目录 前言一、接口抓包二、逆向分析3. 接口验证总结 前言 出于对数据安全的考虑&#xff0c;现代化的网站/APP通常会对数据接口做加密处理。而分析这些接口的加密算法并实现模拟调用的过程就叫做「逆向」。逆向对于爬虫工程师来说是一个永远绕不开的话题&#xff0c;也逐渐…

《嵌入式存储器架构、电路与应用》----学习记录(四)

第5章 新型嵌入式存储器 在现有主流嵌入式存储器中&#xff0c;SRAM虽然读写速度非常快&#xff0c;但是单元面积太大&#xff0c;无法在片上实现高密度集成&#xff1b;DRAM由于要制造电容&#xff0c;所采用的工艺无法在先进的CMOS工艺中实现&#xff0c;不利于做嵌入式存储…

六一专辑||C++实现动态烟花代码

首先&#xff0c;祝大家儿童节快乐&#xff01; 在这篇文章中&#xff0c;将用烟花致以大家最好的祝福&#xff01; 烟花代码将会用到 Easyx 图形库&#xff0c;可以去官网下载&#xff1a;easyx.cnhttp://easyx.cn/ 代码思路 1 烟花结构体 2 初始化烟花 3 烟花上升 4 烟…

设置主机名和host映射

这里写目录标题 设置主机名设置host映射主机名解析过程分析 设置主机名 为了方便记忆。可以给linux系统主机名&#xff0c;也可以根据需要修改主机名 指令hostname来查看主机名 修改主机名 vim /etc/hostname 进入之后修改就行 修改之后重启生效 设置host映射 如何通过主机…

分布式锁实现原理

为什么需要分布式锁&#xff1f; 本地锁synchronized只能锁住当前服务进程&#xff0c;一个本地锁只能锁一个服务&#xff0c;如果是分布式服务情况下使用本地锁&#xff0c;那么多少服务就会有多少进程同时执行&#xff0c;就是去了锁的效果&#xff0c;为了到达分布式情况下…

3.9 流水作业调度问题

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 1.我对流水调度问题的理解 流水作业调度问题是动态规划中的一个经典问题&#xff0c;它涉及将一系列作业分配给多个工作站以最小化总完成时间。该问题的…

go test 包外测试

之前文章有介绍过 go test coverage 单测覆盖率 和Go test基础用法&#xff0c;今天这里主要介绍 go 单测中比较特殊的一种场景&#xff1a;包外测试。初次看到这个名字&#xff0c;我还以为就是单独创建一个新目录&#xff0c;所有的单测用例统一都汇总到这个目录下&#xff0…

【P48】JMeter 断言持续时间(Duration Assertion)

文章目录 一、断言持续时间&#xff08;Duration Assertion&#xff09;参数说明二、测试计划设计 一、断言持续时间&#xff08;Duration Assertion&#xff09;参数说明 可以控制取样器的执行是否超过某个时间&#xff0c;如果超时则报错&#xff0c;持续时间断言器也叫超时…

21天学会C++:Day6----内联函数

CSDN的uu们&#xff0c;大家好。这里是C入门的第六讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. 知识点讲解 2.1 内联函数的使用 2.2 内联函数的特性 2.2 …