C++自定义函数详解

个人主页:PingdiGuo_guo

收录专栏:C++干货专栏

铁汁们新年好呀,今天我们来了解自定义函数。

文章目录

1.数学中的函数

2.什么是自定义函数

3.自定义函数如何使用?

4.值传递和引用传递(形参和实参区分)

1.值传递

2. 引用传递

3. 形参与实参的区别

5.自定义递归函数

6.嵌套调用和链式调用

1.链式调用

2.嵌套调用

7.自定义函数和库函数的对比

8.自定义函数的练习

9.总结


1.数学中的函数

在数学中,函数是一种基本的数学对象,它建立了一个集合(称为定义域)中的每个元素与另一个集合(称为值域)中的唯一元素之间的对应关系。简单地说,函数就是一个规则,它接收一个或多个输入值(也称为自变量),并据此产生一个确定的输出值(称为函数值或因变量)。

数学上的函数通常用 ( f ) 表示,并写作 ( y = f(x) ),这里的 ( x ) 是自变量,( y ) 是相应于 ( x ) 的函数值。例如,线性函数 ( f(x) = mx + b ) 就是一条直线的方程,其中 ( m ) 是斜率,( b ) 是截域。

2.什么是自定义函数

自定义函数是在C++或其他编程语言中由程序员自行创建的函数,用于封装一组操作或计算逻辑,以便在多个地方重复使用或者模块化代码。自定义函数允许开发者按照自己的需求来定制功能,并且可以根据程序的具体情况调整其行为。
 

3.自定义函数如何使用?

1. 声明函数原型:
在函数体之前(通常在头文件或源文件的开始部分),你需要声明函数,包括返回类型、函数名以及参数列表(如果有的话):

 

// 声明一个自定义函数原型
double calculateArea(double radius);



这个例子声明了一个名为calculateArea的函数,它接受一个double类型的参数(半径),并返回一个double类型的值(面积)。

2. 定义函数体:
在函数声明之后,你需要定义函数的实际实现,即写出完成特定任务的代码块:

 

// 定义函数体
double calculateArea(double radius) {
double area = 3.14159 * radius * radius;
return area;
}



3. 调用函数:
在程序的适当位置,你可以像使用库函数一样调用自定义函数:


 

int main() {
double myRadius = 5.0;
double result = calculateArea(myRadius);
cout << "The area of the circle with radius " << myRadius << " is: " << result << endl;
return 0;
}

4.值传递和引用传递(形参和实参区分)

1.值传递

- 当函数通过值传递方式接收参数时,它会创建实参的副本(复制一份实参的值)并将这个副本传递给函数内部的形参。
- 形参的变化不会影响实参,因为两者存储在不同的内存位置。
- 值传递通常适用于不需要修改实参值的情况。

示例:

void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swapByValue(x, y); // 调用函数后,x和y的值不变,因为交换的是函数内部形参的值
}




2. 引用传递


- 引用传递是将实参的引用(也就是实参的别名)传递给函数的形参,这样形参就直接指向实参的内存地址。
- 如果在函数内部改变了引用类型的形参,那么相应地,实参的值也会被修改。
- 引用传递常用于需要更改实参或避免大型数据结构复制的成本时。

示例:
 

void swapByReference(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swapByReference(x, y); // 调用函数后,x和y的值会互换,因为函数内部修改的是实参的内存
}




3. 形参与实参的区别


- 实参(Actual Parameter):在函数调用过程中,传递给函数的实际值。例如上面例子中的 x和 y 就是实参。

- 形参(Formal Parameter):在函数定义中,用来接收传递进来的值的变量。如上述例子中的 a 和 b 是形参,它们在函数内部代表了从外部传入的值。

总结来说,在函数调用过程中,实参是实际提供的值,而形参是函数声明中用来接收这些值的地方。在C++中,值传递和引用传递决定了函数操作的是实参的副本还是实参本身。

5.自定义递归函数

递归调用函数是在函数内部调用自身的一种编程技术。这种技术在解决具有自我重复性质的问题时非常有用,如树的遍历、动态规划中的某些子问题解法、分治算法中的问题拆解等。

递归函数通常包含两个基本部分:
- 基本情况(Base Case):这是递归结束的条件,即当达到某个特定条件时,不再进行下一层递归调用,而是直接返回一个确定的结果。
- 递归步骤(Recursive Step):在此阶段,函数通过调用自身来解决规模更小的相同问题,直到满足基本情况为止。

下面是一个简单的递归函数示例,计算阶乘(Factorial):

 

#include <iostream>

// 递归函数实现阶乘
int factorial(int n) {
// 基本情况:0的阶乘为1
if (n == 0)
return 1;
// 递归步骤:n的阶乘等于n乘以(n-1)的阶乘
else
return n * factorial(n - 1);
}

int main() {
int num = 5;
std::cout << "The factorial of " << num << " is: " << factorial(num) << std::endl;
return 0;
}


在这个例子中,factorial 函数在每次递归调用时都会将问题规模缩小(减少参数n的值),直到遇到基本情况n为0时停止递归,然后逐层返回计算结果。

6.嵌套调用和链式调用

1.链式调用

链式调用是一种编程风格,可以在调用多个方法时使用点操作符将它们连接在一起,形成一个链。在每个方法调用后,都会返回一个对象,可以继续调用其他方法。这样就可以在一行代码中实现多个方法的调用,使代码更加简洁和可读性更高。

步骤一:定义一个支持链式访问的类

 

class Chainable {
public:
// 构造函数
Chainable(int initial_value) : value(initial_value) {}

// 第一个链式方法(假设增加值)
Chainable& increment(int step = 1) {
value += step;
return *this; // 返回当前对象的引用以支持链式调用
}

// 第二个链式方法(假设加倍)
Chainable& doubleValue() {
value *= 2;
return *this;
}
private:
int value;
};



步骤二:创建对象并开始链式调用

 

int main() {
// 创建Chainable对象
Chainable obj(5);

// 链式访问与调用
obj.increment(3).doubleValue();

// 这里原本可能还有其他方法继续调用...
// ...

// 最终可以验证对象的值
std::cout << "Final value: " << obj.value << std::endl;

return 0;
}



在上述代码中,首先定义了一个名为Chainable的类,它有两个链式方法:increment()和doubleValue()。这两个方法都在执行相应的操作之后返回了对当前对象的引用,使得可以连续调用这些方法,形成链式调用。在main()函数中展示了如何使用这种方式连续调用两个方法来处理同一个对象。

2.嵌套调用

嵌套调用是指在一个方法内部调用另一个方法,并且被调用的方法又可以继续调用其他方法,形成多层嵌套的调用关系。嵌套调用可以在程序中实现复杂的逻辑和功能,将代码进行模块化和组合,提高代码的可复用性和可维护性。

在嵌套调用中,每个方法的返回值可以作为下一个方法的参数,这样可以将多个方法串联起来,实现一系列的操作。嵌套调用的层级可以根据具体需求进行设计,可以是两层、三层,甚至更多。

步骤1:定义一个包含内部函数的外部函数:
 

void outerFunction(int x) {
// ...
void innerFunction();
// ...
}


步骤2:定义内部函数的具体实现:
 

void outerFunction(int x) {
std::cout << "In outer function with x = " << x << std::endl;

void innerFunction() {
std::cout << "In inner function." << std::endl;
}
}


步骤3:在外部函数内部调用内部函数:
 

void outerFunction(int x) {
// ...
innerFunction(); // 这里是嵌套调用发生的地方
// ...
}


步骤4:完整外部函数及其调用示例:

void outerFunction(int x) {
std::cout << "In outer function with x = " << x << std::endl;

void innerFunction() {
std::cout << "In inner function." << std::endl;
}

innerFunction();

std::cout << "Continuing in outer function after inner call." << std::endl;
}

int main() {
outerFunction(5); // 在主函数中调用outerFunction
return 0;
}



输出:
 

In outer function with x = 5
In inner function.
Continuing in outer function after inner call.

7.自定义函数和库函数的对比

- 自定义函数:
- 由程序员根据具体需求编写。
- 可以自由命名,具有高度灵活性。
- 具体实现完全取决于程序员,可修改、优化或扩展。
- 只能在包含它们的源文件或链接到它们的库中调用。

- 库函数:
- 预先编写好的、经过充分测试的标准函数,通常由语言本身或第三方库提供。
- 名称和功能通常是标准化的,如C++标准库中的std::sort()、std::cos()等。
- 不需要程序员重新实现,只需包含适当的头文件并在程序中正确调用即可。
- 通常跨平台兼容性更好,因为它们遵循语言规范和标准。
- 提供的功能广泛多样,涵盖基础数据结构操作、数学计算、输入/输出处理等多个方面。

总结来说,自定义函数的核心价值在于它可以针对性地解决特定的问题,并且有助于提高代码的复用性和组织性;而库函数则是为了提供通用的、高效的功能组件,减少重复劳动,提升开发效率和程序质量。

8.自定义函数的练习

假设我们要编写一个C++函数,它接受两个整数作为参数,返回它们的最大公约数(Greatest Common Divisor, GCD)。这个功能可以通过使用欧几里得算法(Euclidean algorithm)来实现。下面是这个函数的定义和使用示例:

 

#include <iostream>

// 自定义函数:计算两个整数的最大公约数
int gcd(int a, int b) {
// 边界条件:如果b为0,则a就是最大公约数
if (b == 0)
return a;

// 否则,递归地计算(a mod b)和b的最大公约数
return gcd(b, a % b);
}

int main() {
int num1 ,num2 ;
std::cin>>num1>>num2;

// 调用自定义函数并输出结果
std::cout << "The Greatest Common Divisor (GCD) of " << num1 << " and " << num2 << " is: " << gcd(num1, num2) << std::endl;

return 0;
}



上述代码首先定义了一个名为gcd的函数,该函数采用两个整数作为参数,并使用递归方法找到它们的最大公约数。在main函数中,我们创建了两个变量并调用了gcd函数来计算它们的最大公约数,最后将结果输出到控制台。

9.总结

本篇博客到这里就结束了,感谢大家的支持与观看,如果有好的建议欢迎留言,谢谢大家啦!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电脑服务器离线安装.net framework 3.5解决方案(错误:0x8024402c )(如何确定当前系统是否安装NET Framework 3.5)

问题环境&#xff1a; 日常服务的搭建或多或少都会有需要到NET Framework 3.5的微软程序运行框架&#xff0c;本次介绍几种不同的安装方式主要解决运行在Windows 2012 以上的操作系统的服务。 NET Framework 3.5 是什么&#xff1f; .NET Framework是微软公司推出的程序运行框架…

【超高效!保护隐私的新方法】针对图像到图像(l2l)生成模型遗忘学习:超高效且不需要重新训练就能从生成模型中移除特定数据

针对图像到图像生成模型遗忘学习&#xff1a;超高效且不需要重新训练就能从生成模型中移除特定数据 提出背景如何在不重训练模型的情况下从I2I生成模型中移除特定数据&#xff1f; 超高效的机器遗忘方法子问题1: 如何在图像到图像&#xff08;I2I&#xff09;生成模型中进行高效…

Nginx与history路由模式:刷新页面404问题

使用nginx部署前端项目&#xff0c;路由模式采用history模式时&#xff0c;刷新页面之后&#xff0c;显示404。 路由模式 前端路由的基本作用为&#xff1a; ①当浏览器地址变化时&#xff0c;切换页面&#xff1b; ②点击浏览器后退、前进按钮时&#xff0c;更新网页内容&…

双面板设计的一套经验规则-笔记

过大的分布电感导致信号地干扰也就是地弹(专业名词) 还有就是输出瞬态电流导致的地弹 图中可以看到最高 0.5V 的信号地干扰&#xff0c;这只是单一块开发板的测试结果。如果接上外围电路&#xff0c;甚至面包板电路可以想象噪声水平可能会更高。 双面电路板 经验规则 下面来…

Tomcat 原理分析

1、Tomcat 的组成 如下图&#xff1a; Tomcat组成 Server&#xff1a; Tomcat 封装的、对外提供完整的、基于组件的 web 服务&#xff0c;包含 Connectors、Container 两个核心组件&#xff0c;以及多个功能组件&#xff0c;各个 Service 之间是独立的&#xff0c;但是共享 同…

【数据结构】前缀树的模拟实现

目录 1、什么是前缀树&#xff1f; 2、模拟实现 2.1、前缀树节点结构 2.2、字符串的添加 2.3、字符串的查寻 2.3.1、查询树中有多少个以字符串"pre"作为前缀的字符串 2.3.2、查询某个字符串被添加过多少次 2.4、字符串的删除 3、完整代码 1、什么是前缀树&…

Flink 2.0 状态存算分离改造实践

本文整理自阿里云智能 Flink 存储引擎团队兰兆千在 FFA 2023 核心技术&#xff08;一&#xff09;中 的分享&#xff0c;内容关于 Flink 2.0 状态存算分离改造实践的研究&#xff0c;主要分为以下四部分&#xff1a; Flink 大状态管理痛点 阿里云自研状态存储后端 Gemini 的存…

Linux下的crontab定时执行任务命令详解

在LINUX中&#xff0c;周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron]。cron读取一个或多个配置文件&#xff0c;这些配置文件中包含了命令行及其调用时间。 cron的配置文件称为“crontab”&#xff0c;是“cron table”的简写。 一、cron服务   cron是一个…

为什么要进行FTP替代?专业的FTP替代方案了解一下!

FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;的历史可以追溯到20世纪70年代&#xff0c;这是一个由美国国防部资助的早期计算机网络&#xff0c;后来发展成为互联网的前身。随着时间的推移&#xff0c;FTP经历了多次迭代和改进&#xff0c;以适…

有关网络安全的课程学习网页

1.思科网络学院 免费学习skillsforall的课程 课程链接&#xff1a;Introduction to Cybersecurity by Cisco: Free Online Course (skillsforall.com) 2.斯坦福大学计算机和网络安全基础 该证书对于初学者来说最有价值&#xff0c;它由最著名的大学之一斯坦福大学提供。您可…

【动态规划】【C++算法】2518. 好分区的数目

作者推荐 【动态规划】【前缀和】【C算法】LCP 57. 打地鼠 本文涉及知识点 动态规划汇总 LeetCode:2518. 好分区的数目 给你一个正整数数组 nums 和一个整数 k 。 分区 的定义是&#xff1a;将数组划分成两个有序的 组 &#xff0c;并满足每个元素 恰好 存在于 某一个 组中…

AVR 328pb ADC基本介绍和使用

AVR 328pb ADC基本介绍和使用 &#x1f4cd;结合参考同架构lgt8f328p中文文档&#xff1a;http://www.prodesign.com.cn/wp-content/uploads/2023/03/LGT8FX8P_databook_v1.0.4.pdf &#x1f4d8;328pb ADC特性 • 10-bit Resolution 10位分辨率 • 0.5 LSB Integral Non-lin…

猫头虎分享已解决Bug || JavaScript语法错误(Syntax Error):SyntaxError: Unexpected token

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

leetcode(哈希表)49.字母异位词分组(C++详细解释)DAY5

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 示例 1: 输入: strs [“eat”, “tea”…

Golang的for循环变量和goroutine的陷阱,1.22版本的更新

先来看一段golang 1.22版本之前的for循环的代码 package mainimport "fmt"func main() {done : make(chan bool)values : []string{"chen", "hai", "feng"}for _, v : range values {fmt.Println("start")go func() {fmt.P…

Elasticsearch(四)

是这样的前面的几篇笔记&#xff0c;感觉对我没有形成知识体系&#xff0c;感觉乱糟糟的&#xff0c;只是大概的了解了一些基础知识&#xff0c;仅此而已&#xff0c;而且对于这技术栈的学习也是为了在后面的java开发使用&#xff0c;但是这里的API学的感觉有点乱&#xff01;然…

JavaScript 入门 完整版

目录 第一个知识点&#xff1a;引入js文件 内部引用: 外部引用: 第二个知识点&#xff1a;javascript的基本语法 定义变量&#xff1a; 条件控制(if - else if - else) 第三个知识点&#xff1a;javascript里的数据类型、运算符&#xff1a; 数字类型 字符串类型 布尔…

前端JavaScript篇之对执行上下文的理解

目录 对执行上下文的理解创建执行上下文 对执行上下文的理解 当我们在执行JavaScript代码时&#xff0c;JavaScript引擎会创建并维护一个执行上下文栈来管理执行上下文。执行上下文有三种类型&#xff1a;全局执行上下文、函数执行上下文和eval函数执行上下文。 在写代码的时…

FRP内网穿透需要注意的事情

安全性 SSH设置好密钥后&#xff0c;一定要关闭密码登陆。现在暴力破解策略往往是先派小鸡端口扫描看看谁可以密码访问&#xff0c;如果可以&#xff0c;然后定点爆破就开始了。不允许root登陆。FRP使用token验证。FRP服务端要输出配置文件&#xff0c;info等级就能显示访问ip…

mac docker 宿主机和容器间网络打通

动因 是这样&#xff0c;笔者最近满怀欣喜入手Docker&#xff0c;看着各种文章命令都是不断点头称道&#xff1a;“嗯嗯&#xff0c;不错不错”,在接下来终于准备大干一场的时候碰壁了&#xff0c;主要情况是说在Mac中跑了第一把的时候发现碰到&#xff0c;虚拟机和宿主机居然…