- C++
C++ 函数
- 2025-5-28 19:57:39 @
🧠 C++ 函数教程(零基础也能看懂)
📚 从函数是什么,到怎么写函数,手把手带你入门!
🔰 一、什么是函数?
在编程中,函数(Function) 就像一个“小工厂”——你给它一些原料(输入),它按照规则加工后给你成品(输出)。
✅ 简单理解:
- 函数 = 功能块
- 把重复使用的代码封装起来,方便以后调用。
- 像数学中的
f(x) = x + 1
一样,给它一个值,它返回结果。
💡 二、为什么要使用函数?
好处 | 解释 |
---|---|
🔄 复用性高 | 写一次,可以多次调用 |
🧹 结构清晰 | 让代码更整洁,容易维护 |
🎯 模块化设计 | 把大问题拆成小问题,逐个解决 |
🛠️ 三、函数的定义格式(语法)
返回类型 函数名(参数列表) {
// 函数体:你要执行的代码
return 返回值;
}
🧾 示例:
int add(int a, int b) {
int result = a + b;
return result;
}
🧩 四、函数的组成部分详解
1. 返回类型(Return Type)
表示这个函数会返回什么类型的数据。例如:
int
→ 整数double
→ 浮点数void
→ 不返回任何内容
2. 函数名(Function Name)
自定义的名字,要简短有意义,符合命名规范(如 add
, printHello
)。
3. 参数列表(Parameters)
括号里是传入函数的数据,可以有多个参数,也可以没有参数。
👉 参数就像原材料,供函数内部使用。
4. 函数体(Function Body)
花括号 {}
中的内容,就是函数实际要做的事情。
5. return 返回值
函数执行完后,把结果返回给调用者。
🧪 五、函数的使用步骤(完整例子)
📘 示例:计算两个数的和
#include <iostream>
using namespace std;
// 定义函数
int add(int a, int b) {
int sum = a + b;
return sum;
}
int main() {
// 调用函数
int result = add(3, 5);
cout << "3 + 5 = " << result << endl;
return 0;
}
✅ 输出结果:
3 + 5 = 8
📌 六、函数的分类(常见类型)
1. 无参数无返回值
void printHello() {
cout << "Hello World!" << endl;
}
2. 有参数无返回值
void printSum(int a, int b) {
cout << "Sum is: " << a + b << endl;
}
3. 有参数有返回值
int multiply(int a, int b) {
return a * b;
}
🧱 七、函数调用流程图解(文字版)
main函数开始
↓
调用add函数(传入3和5)
↓
add函数执行a + b
↓
返回8
↓
main函数接收并打印
🧑🏫 八、函数的注意事项(新手常踩坑的地方)
注意事项 | 说明 |
---|---|
📝 函数必须先定义再使用 | 否则编译器不认识你写的函数 |
🧮 参数顺序不能错 | 传参时要和定义一致 |
🔄 函数不能嵌套定义 | C++不允许在一个函数里定义另一个函数 |
📌 void 表示不返回值 |
如果不需要返回值,就用 void 声明 |
🧰 九、实战练习题(附答案)
✅ 题目1:写一个函数,判断一个数是否为偶数
bool isEven(int num) {
return num % 2 == 0;
}
✅ 题目2:写一个函数,返回三个数中的最大值
int maxOfThree(int a, int b, int c) {
if (a > b && a > c)
return a;
else if (b > c)
return b;
else
return c;
}
🧠 十、总结(函数要点一览表)
项目 | 内容 |
---|---|
函数作用 | 封装代码、提高复用性 |
函数组成 | 返回类型、函数名、参数、函数体、return |
函数调用 | 在main函数中调用即可 |
注意事项 | 先定义、参数顺序正确、不能嵌套定义 |
🎯 十一、鼓励语
同学们,函数就像是我们程序的积木块,学会写函数,你就掌握了编程的核心能力之一!不要怕写错,多练多改,你一定能写出漂亮的函数!加油!💪
📘 下节课预告:数组与函数结合使用
📌 想知道怎么让函数处理一组数据吗?下一讲我们将学习如何用函数操作数组!
10 条评论
-
admin SU @ 2025-5-29 20:41:32
#include <iostream> #include <string> using namespace std; template <typename T = int> T multiply(T a, T b) { return a * b; } int main() { int res1 = multiply(5, 3); // T= int(默认) cout<<res1<<endl; double res2 = multiply(5.4, 3.7); cout<<res2<<endl; double res3 = multiply<double>(2.5, 4.0); // T= double cout<<res3<<endl; return 0; }
-
2025-5-29 20:33:07@
#include <iostream> #include <string> using namespace std; // 定义函数模板:求两个数的最大值 template <typename T> T max1(T a, T b) { return a > b ? a : b; } int main() { // 自动类型推导调用 int i = max1(10, 20); // 生成int max(int, int) double d = max1(3.14, 2.71); // 生成double max(double, double) string s = max1("apple", "banana"); // 生成string max(string, string) cout << i << endl; // 输出20 cout << d << endl; // 输出3.14 cout << s << endl; // 输出banana(按字典序比较) // 显式指定类型调用 double x = max1<double>(5, 3); // 等价于max(5, 3) cout<<sizeof(max1<double>(5, 3))<<endl; return 0; }
-
2025-5-29 20:28:13@
#include<iostream> using namespace std; // 示例:求最大值的函数模板 template <typename T> T max1(T a, T b) { return a > b ? a : b; } int main() { cout<<max1(4,6)<<endl; cout<<max1(4.5,5.6)<<endl; return 0; }
-
2025-5-29 20:23:17@
#include <iostream> using namespace std; // 函数1 void func(char ch){ cout<<"#1"<<endl; } // 函数3 void func(long m){ cout<<"#3"<<endl; } // 函数4 void func(double f){ cout<<"#4"<<endl; } int main(){ short s = 99; float f = 84.6; func('a'); // 精确匹配func(char),输出#1 func((long)s); // 这里会出现问题,short可转换为int、long等,编译器不知道匹配哪个函数 func(49L); // 同样,49是int,可转换为long等,编译器无法确定调用哪个函数 func(f); // 将float转换成double,调用func(double),输出#4 return 0; }
-
2025-5-29 20:16:06@
海伦公式: 假设在平面内,有一个三角形,边长分别为a、b、c,三角形的面积S可由以下公式求得:
而公式里的p为半周长(周长的一半):
-
2025-5-29 20:11:39@
一、函数重载的概念
在C++中,函数重载允许在同一个作用域(比如同一个类、同一个命名空间等)内定义多个同名函数,只要它们的参数列表不同即可。参数列表也叫参数签名,包括参数的类型、个数和顺序,只要其中有一个不同,就认为参数列表不同。函数的返回类型可以相同也可以不同,但仅返回类型不同不能作为函数重载的依据。
借助函数重载,一个函数名可以有多种用途。例如在实际开发中,可能需要交换不同类型变量的值,如
int
、float
、char
等类型。在C语言中可能需要分别定义不同名字的函数来实现,但在C++中通过函数重载,使用同一个函数名就可以实现 。二、函数重载的规则
- 函数名相同:所有重载函数必须具有相同的函数名。
- 参数列表不同:参数的类型、个数或顺序至少有一个方面存在差异。例如:
void func(int a); // 参数为int类型 void func(double b); // 参数为double类型,与上一个函数参数类型不同,构成重载 void func(int a, double b); // 参数个数和顺序与前面函数不同,构成重载
- 返回类型无关:函数的返回类型可以相同也可以不同,但仅返回类型不同不能构成函数重载。比如下面这种情况是不合法的:
int func(int a); double func(int a); // 错误,仅返回类型不同,不构成重载
- 作用域相同:重载的函数必须定义在同一个作用域内,比如都在全局作用域,或者都在同一个类的内部等。
三、函数重载示例
以下是通过函数重载实现计算不同图形面积的示例:
#include <iostream> #include <cmath> using namespace std; // 计算圆形面积 double calculateArea(double radius) { return 3.14159 * radius * radius; } // 计算矩形面积 double calculateArea(double length, double width) { return length * width; } // 计算三角形面积(使用海伦公式) double calculateArea(double base, double height, double side1, double side2) { double s = (base + height + side1 + side2) / 2; return sqrt(s * (s - base) * (s - height) * (s - side1) * (s - side2)); } int main() { double circleRadius = 5.0; double rectangleLength = 4.0, rectangleWidth = 3.0; double triangleBase = 3.0, triangleHeight = 4.0, triangleSide1 = 5.0, triangleSide2 = 6.0; cout << "圆形面积: " << calculateArea(circleRadius) << endl; cout << "矩形面积: " << calculateArea(rectangleLength, rectangleWidth) << endl; cout << "三角形面积: " << calculateArea(triangleBase, triangleHeight, triangleSide1, triangleSide2) << endl; return 0; }
在这个示例中,
calculateArea
函数被重载了三次,分别用于计算圆形、矩形和三角形的面积,编译器会根据传入参数的不同来调用相应的函数。四、C++实现函数重载的原理
C++代码在编译时,编译器会根据参数列表对函数进行重命名。例如
void Swap(int a, int b)
可能会被重命名为_Swap_int_int
,void Swap(float x, float y)
可能会被重命名为_Swap_float_float
。当发生函数调用时,编译器会根据传入的实参去逐个匹配这些重命名后的函数,以选择对应的函数,如果匹配失败,编译器就会报错,这个过程叫做重载决议(Overload Resolution) 。不同的编译器重命名方式可能不同。五、函数重载过程中的二义性和类型转换问题
当实参的类型和形参的类型不一致时,编译器需要进行类型转换来匹配函数,这可能会导致一些复杂情况。例如:
#include <iostream> using namespace std; // 函数1 void func(char ch){ cout<<"#1"<<endl; } // 函数3 void func(long m){ cout<<"#3"<<endl; } // 函数4 void func(double f){ cout<<"#4"<<endl; } int main(){ short s = 99; float f = 84.6; func('a'); // 精确匹配func(char),输出#1 func(s); // 这里会出现问题,short可转换为int、long等,编译器不知道匹配哪个函数 func(49); // 同样,49是int,可转换为long等,编译器无法确定调用哪个函数 func(f); // 将float转换成double,调用func(double),输出#4 return 0; }
C++标准规定,在进行重载决议时编译器按照以下优先级顺序来处理实参的类型:
- 精确匹配:不做类型转换,直接匹配。
- 微不足道的转换:例如从数组名到数组指针、从函数名到指向函数的指针、从非
const
类型到const
类型等转换 。
在编写重载函数时,要尽量避免出现这种让编译器难以抉择的情况,以防止出现二义性错误。
六、函数重载的优势与注意事项
- 优势:
- 提高代码可读性:通过使用同一个函数名来处理相似功能,使代码更直观易懂。比如都用
calculateArea
表示计算面积相关操作,而不是定义多个不同名的面积计算函数。 - 增强代码复用性:减少了为相似功能编写大量不同名称函数的工作,提高了代码的复用程度。
- 提高代码可读性:通过使用同一个函数名来处理相似功能,使代码更直观易懂。比如都用
- 注意事项:
- 避免命名冲突:确保在同一作用域内,不会出现参数列表完全相同的重载函数,否则编译器会报错。
- 合理使用默认参数:注意默认参数与函数重载结合使用时可能产生的问题,例如可能导致调用的不确定性。
- 避免过度重载:过多的重载函数可能会降低代码的可读性和可维护性,也可能影响编译时间 。
-
2025-5-28 20:00:18@
C++ 函数模板(Function Templates)完全指南
一、为什么需要函数模板?
假设我们需要实现一个求两个数最大值的函数:
- 对于
int
类型:int maxInt(int a, int b) { return a > b ? a : b; }
- 对于
double
类型:double maxDouble(double a, double b) { ... }
- 对于
string
类型:string maxString(string a, string b) { ... }
问题:功能相同但类型不同的函数需要重复编写,代码冗余。
解决方案:使用函数模板,让编译器自动生成对应类型的函数。二、函数模板的基本语法
// 模板定义 template <typename 类型参数> 返回类型 函数名(参数列表) { // 函数体(使用类型参数) } // 示例:求最大值的函数模板 template <typename T> T max(T a, T b) { return a > b ? a : b; }
三、函数模板的使用示例
#include <iostream> #include <string> using namespace std; // 定义函数模板:求两个数的最大值 template <typename T> T max(T a, T b) { return a > b ? a : b; } int main() { // 自动类型推导调用 int i = max(10, 20); // 生成int max(int, int) double d = max(3.14, 2.71); // 生成double max(double, double) string s = max("apple", "banana"); // 生成string max(string, string) cout << i << endl; // 输出20 cout << d << endl; // 输出3.14 cout << s << endl; // 输出banana(按字典序比较) // 显式指定类型调用 int x = max<int>(5, 3); // 等价于max(5, 3) return 0; }
四、模板参数的多种形式
- 单个类型参数(如
typename T
) - 多个类型参数:
template <typename T, typename U> T add(T a, U b) { // 允许不同类型参数 return a + b; } int main() { double result = add(10, 3.5); // 生成add<int, double>(int, double) cout << result << endl; // 输出13.5 return 0; }
- 默认类型参数(C++11支持):
template <typename T = int> T multiply(T a, T b) { return a * b; } int main() { int res1 = multiply(5, 3); // T= int(默认) double res2 = multiply<double>(2.5, 4.0); // T= double return 0; }
五、函数模板与普通函数的区别
特性 普通函数 函数模板 定义方式 直接声明类型 需要 template
关键字类型处理 处理固定类型 类型在调用时确定 实例化时机 编译时直接存在 调用时生成对应类型的函数 代码复用 功能相同的不同类型需重复编写 一套代码处理所有类型 类型安全 编译时检查类型 同样具有类型检查 六、函数模板的实例化过程
- 调用模板函数:
max(10, 20);
- 编译器推导类型:确定
T
为int
- 生成具体函数:
int max(int a, int b) { return a > b ? a : b; }
- 执行函数:返回20
七、函数模板的限制与注意事项
- 类型必须支持函数体内的操作:
template <typename T> T add(T a, T b) { return a + b; // T必须支持+运算符 }
错误用法:对自定义类调用
add
,若类未重载+
运算符会编译错误。-
模板参数推导规则:
- 优先匹配普通函数,若没有匹配才使用模板
- 可显式指定类型:
max<double>(3.1, 2.5)
-
模板不是宏:
- 宏是简单文本替换(无类型检查)
- 模板是类型安全的泛型编程工具
八、实战案例:实现通用交换函数
#include <iostream> using namespace std; // 交换函数模板 template <typename T> void swap(T& a, T& b) { T temp = a; a = b; b = temp; } int main() { // 交换整数 int x = 10, y = 20; swap(x, y); cout << "x=" << x << ", y=" << y << endl; // 输出x=20, y=10 // 交换字符串 string s1 = "apple", s2 = "banana"; swap(s1, s2); cout << "s1=" << s1 << ", s2=" << s2 << endl; // 输出s1=banana, s2=apple return 0; }
九、进阶:函数模板与函数重载
当模板无法处理特定类型时,可重载普通函数:
#include <iostream> #include <cstring> using namespace std; // 通用模板 template <typename T> T max(T a, T b) { return a > b ? a : b; } // 重载:处理C风格字符串(char*) const char* max(const char* a, const char* b) { return strcmp(a, b) > 0 ? a : b; } int main() { cout << max("hello", "world") << endl; // 调用重载函数,输出world cout << max<int>(5, 3) << endl; // 调用模板函数,输出5 return 0; }
十、练习题
- 编写模板函数
min(T a, T b)
,返回两个数的最小值。 - 实现模板函数
printArray(T arr[], int n)
,打印数组所有元素。 - 设计模板函数
isEqual(T a, T b)
,判断两个值是否相等(需考虑==
运算符支持)。
十一、总结
函数模板是C++泛型编程的基础,它允许用一套代码处理多种数据类型,避免重复编写相似功能的函数。通过
template
关键字和类型参数(如typename T
),编译器会在调用时自动生成对应类型的函数,既保证了类型安全,又提高了代码复用性。掌握函数模板后,后续可进一步学习类模板(Class Templates),实现更复杂的泛型数据结构(如vector、map等STL容器)。
- 对于
-
2025-5-28 19:59:34@
🧠 C++ 函数模板(Function Templates)
📚 一文看懂函数模板,零基础也能轻松掌握!
💡 一、什么是函数模板?
在C++中,函数模板就像是一个“万能公式”,可以让你写出适用于多种数据类型的通用函数,而不需要为每种类型都单独写一遍。
✅ 简单理解:
- 函数模板 = 写一次,多种类型都能用
- 类似于数学中的通用公式:
f(x, y) = x + y
,不管x和y是整数、浮点数还是字符串,都可以使用
🔍 二、为什么要使用函数模板?
好处 说明 🔄 代码复用 同一个函数逻辑可以用于不同数据类型 🧹 减少重复代码 避免为 int
、double
、string
等分别写多个函数🎯 提高可维护性 修改一处,影响所有类型
🛠️ 三、函数模板的基本语法
template <typename T> 返回类型 函数名(T 参数1, T 参数2, ...) { // 函数体 return 返回值; }
template <typename T>
:定义一个模板,T 是一个占位符类型- 在调用时,编译器会根据传入的参数自动推导出具体类型
🧪 四、函数模板示例讲解
✅ 示例1:实现两个值的最大值比较
#include <iostream> using namespace std; // 定义模板函数 template <typename T> T maxVal(T a, T b) { return (a > b) ? a : b; } int main() { cout << "max int: " << maxVal(3, 5) << endl; // 输出:5 cout << "max double: " << maxVal(3.5, 2.8) << endl; // 输出:3.5 cout << "max char: " << maxVal('a', 'z') << endl; // 输出:z return 0; }
📌 说明:
- 编译器会自动为
int
、double
、char
分别生成对应的函数版本 - 不需要手动重载多个函数
🧩 五、函数模板的注意事项
注意事项 解释 ⚠️ 类型必须支持操作 如果你用了 >
操作符,那传入的类型必须支持这个运算⚠️ 不能自动匹配不同类型 maxVal(3, 5.6)
会报错,因为 T 要求统一类型⚠️ 命名规范建议 通常使用 T
表示类型,也可以用其他名字如Type
🔄 六、函数模板与函数重载的区别
对比项 函数模板 函数重载 使用方式 自动推导类型 手动编写多个函数 适用范围 多个类型共享同一套逻辑 每个类型单独处理 可读性 更简洁 更直观但冗余 维护难度 易维护 修改多个函数麻烦
🧰 七、实战练习题(附答案)
✅ 题目1:写一个模板函数,交换两个变量的值
template <typename T> void swapValues(T &a, T &b) { T temp = a; a = b; b = temp; } int main() { int x = 10, y = 20; swapValues(x, y); cout << "x = " << x << ", y = " << y << endl; // 输出:x = 20, y = 10 double a = 3.14, b = 2.71; swapValues(a, b); cout << "a = " << a << ", b = " << b << endl; // 输出:a = 2.71, b = 3.14 return 0; }
✅ 题目2:写一个模板函数,打印数组内容
#include <iostream> using namespace std; template <typename T> void printArray(T arr[], int size) { for(int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; } int main() { int intArr[] = {1, 2, 3}; double doubleArr[] = {1.1, 2.2, 3.3}; char charArr[] = {'a', 'b', 'c'}; printArray(intArr, 3); // 输出:1 2 3 printArray(doubleArr, 3); // 输出:1.1 2.2 3.3 printArray(charArr, 3); // 输出:a b c return 0; }
🧠 八、总结(函数模板要点一览表)
知识点 内容 模板关键字 template <typename T>
函数模板作用 实现多类型通用逻辑 注意事项 类型需支持对应操作,不支持混合类型 优势 代码复用、结构清晰、易于维护 与重载区别 自动适配 vs 手动适配
🎯 九、鼓励语
同学们,函数模板就像魔法一样,让你写出“一次编写,处处可用”的强大代码!它不仅节省时间,还能提升你的编程思维。继续加油,你离高手只差几个函数模板的距离!💪
📘 下节课预告:类与对象入门(面向对象编程基础)
📌 想知道如何把现实世界的事物映射到程序中?下一讲我们将一起进入 OOP 的世界! -
2025-5-28 19:58:57@
🧠 C++ 函数进阶教程(零基础也能看懂)
📚 函数的参数传递、函数重载、函数调用详解
🔁 一、函数参数传递方式
在C++中,函数的参数可以有多种传递方式:
1. 值传递(Pass by Value)
void changeValue(int x) { x = 100; } int main() { int a = 5; changeValue(a); cout << a; // 输出:5 }
📌 解释:
- 值传递是把变量的值复制一份传给函数。
- 函数内部修改的是副本,不会影响原始变量。
2. 引用传递(Pass by Reference)
void changeValue(int &x) { x = 100; } int main() { int a = 5; changeValue(a); cout << a; // 输出:100 }
📌 解释:
- 引用传递是直接操作原始变量。
- 函数内部对参数的修改会影响原变量。
✅ 使用场景:
- 想要改变实参的值时。
- 传递大型对象(如结构体、类)时,避免复制浪费内存。
3. 指针传递(Pass by Pointer)
void changeValue(int *x) { *x = 100; } int main() { int a = 5; changeValue(&a); cout << a; // 输出:100 }
📌 解释:
- 把变量的地址传入函数。
- 通过指针间接访问和修改变量。
✅ 使用场景:
- 需要修改原始数据。
- 动态内存管理、数组操作等高级功能中常用。
🔍 二、函数重载(Function Overloading)
同一个函数名,根据参数类型或个数不同,执行不同的操作。
✅ 示例:
int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } string add(string a, string b) { return a + b; }
🧪 使用:
cout << add(2, 3) << endl; // 调用 int add(int, int) cout << add(2.5, 3.1) << endl; // 调用 double add(double, double) cout << add("Hello ", "World") << endl; // 调用 string add(string, string)
📌 注意:
- 不能仅靠返回值不同来重载函数。
- 编译器会根据传入的参数自动选择匹配的函数。
🔄 三、函数默认参数(Default Arguments)
给函数参数设置默认值,如果不传参就使用默认值。
✅ 示例:
void greet(string name = "Guest") { cout << "Hello, " << name << "!" << endl; }
🧪 使用:
greet(); // 输出:Hello, Guest! greet("Tom"); // 输出:Hello, Tom!
📌 注意:
- 默认参数必须放在参数列表最后。
- 可以为多个参数设置默认值。
🎮 四、递归函数(Recursion)
函数自己调用自己,常用于解决分治问题(如斐波那契数列、阶乘等)。
✅ 示例:计算阶乘
int factorial(int n) { if (n == 0 || n == 1) { return 1; } return n * factorial(n - 1); }
🧪 使用:
cout << factorial(5); // 输出:120
📌 注意:
- 必须有一个“终止条件”,否则会导致无限递归。
- 递归虽然简洁,但效率不如循环,慎用!
🧩 五、函数与数组结合使用
数组作为参数传递时,实际上是传递了数组的首地址。
✅ 示例:打印数组内容
void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; }
🧪 使用:
int nums[] = {1, 2, 3, 4, 5}; printArray(nums, 5); // 输出:1 2 3 4 5
📌 说明:
arr[]
实际上是一个指针。- 在函数中无法获取数组长度,必须手动传入大小。
🧱 六、函数与结构体结合使用
结构体也可以作为函数参数传递。
✅ 示例:
struct Student { string name; int age; }; void printStudent(Student s) { cout << "Name: " << s.name << ", Age: " << s.age << endl; }
🧪 使用:
Student stu = {"Alice", 20}; printStudent(stu); // 输出:Name: Alice, Age: 20
📌 说明:
- 也可以使用引用传递,提高效率:
void printStudent(const Student &s)
🧪 七、实战练习题(附答案)
✅ 题目1:写一个函数,交换两个整数的值
void swap(int &a, int &b) { int temp = a; a = b; b = temp; }
✅ 题目2:写一个函数,判断一个字符串是否为回文(正读反读一样)
bool isPalindrome(string str) { int left = 0, right = str.length() - 1; while (left < right) { if (str[left] != str[right]) return false; left++; right--; } return true; }
🧠 八、总结(函数进阶知识点一览表)
知识点 内容 参数传递方式 值传递、引用传递、指针传递 函数重载 同名函数,不同参数 默认参数 不传参时使用默认值 递归函数 自己调用自己的函数 函数与数组 传递数组地址 函数与结构体 传递结构体或结构体引用
🎯 九、鼓励语
同学们,函数是编程的灵魂之一。学会灵活使用函数,你就能写出逻辑清晰、结构优雅的程序!继续加油,未来可期!💪
📘 下节课预告:C++ 中的指针与数组深入解析
📌 想知道指针到底是什么?为什么数组和指针关系密切?下一讲我们一起来揭开它们的神秘面纱! -
2025-5-28 19:58:25@
一、函数的基本概念和作用
函数是C++中封装特定功能的代码块,类似于数学中的公式。它可以接收输入(参数),执行操作,并返回结果。例如:
// 计算两个数的和 int add(int a, int b) { return a + b; // 返回a和b的和 }
函数的作用:
- 代码复用:一个函数可以在多个地方被调用,避免重复编写代码。
- 模块化:将复杂问题拆分成小功能模块,使代码更易维护。
- 提高可读性:通过函数名直接反映功能,如
calculateArea()
一看就知道是计算面积。
二、函数的定义和组成部分
1. 函数定义的语法结构
返回类型 函数名(参数列表) { // 函数体(执行具体操作的代码) return 返回值; // 可选,用于返回结果 }
- 返回类型:函数执行后返回的数据类型,如
int
、double
,若无返回值则用void
。 - 函数名:唯一标识符,用于调用函数。
- 参数列表:用逗号分隔的输入参数,如
(int a, int b)
。 - 函数体:用
{}
包裹的代码,包含具体操作。 - 返回语句:
return
语句用于结束函数并返回结果(若返回类型非void
)。
2. 示例:计算矩形面积
// 函数定义 double calculateArea(double length, double width) { double area = length * width; return area; // 返回面积 } // 调用函数 int main() { double area = calculateArea(5.0, 3.0); // 传入参数5.0和3.0 cout << "Area: " << area << endl; // 输出15.0 return 0; }
三、函数的声明和调用
1. 函数声明(函数原型)
在调用函数之前,需要先告诉编译器函数的存在,否则会报错。声明格式为:
返回类型 函数名(参数类型列表); // 末尾加分号,无需函数体
示例:
// 函数声明(在main函数前) double calculateArea(double length, double width); int main() { // 函数调用 double area = calculateArea(5.0, 3.0); return 0; } // 函数定义(在main函数后) double calculateArea(double length, double width) { return length * width; }
2. 函数调用
通过函数名和参数列表调用函数:
// 调用无参数函数 void printHello() { cout << "Hello!" << endl; } int main() { printHello(); // 直接调用 return 0; }
四、参数传递方式
C++支持三种参数传递方式:值传递、引用传递、指针传递。
1. 值传递
- 特点:传递参数的副本,函数内部修改不影响原始变量。
- 示例:
void increase(int num) { num += 10; // 修改的是副本 } int main() { int x = 5; increase(x); // 调用后x仍为5 cout << x << endl; // 输出5 return 0; }
2. 引用传递
- 特点:传递参数的别名,函数内部修改会影响原始变量。
- 语法:在参数类型后加
&
。 - 示例:
void increase(int& num) { // 注意&符号 num += 10; // 修改原始变量 } int main() { int x = 5; increase(x); // 调用后x变为15 cout << x << endl; // 输出15 return 0; }
3. 指针传递
- 特点:传递参数的地址,函数内部通过解引用修改原始变量。
- 语法:参数类型为指针(如
int*
)。 - 示例:
void increase(int* num) { // 接收指针 *num += 10; // 解引用修改原始变量 } int main() { int x = 5; increase(&x); // 传递x的地址 cout << x << endl; // 输出15 return 0; }
五、void函数
- 特点:无返回值,用于执行操作而非返回结果。
- 示例:
void printMessage(string msg) { cout << msg << endl; } int main() { printMessage("Hello, World!"); // 直接调用 return 0; }
六、函数的作用域
- 局部变量:在函数内部定义的变量,仅在函数内可见。
- 全局变量:在所有函数外部定义的变量,整个程序可见。
- 示例:
int globalVar = 10; // 全局变量 void func() { int localVar = 20; // 局部变量 cout << globalVar << endl; // 可以访问全局变量 // cout << localVar << endl; // 其他函数无法访问localVar }
七、递归函数
递归是指函数直接或间接调用自身。必须包含终止条件,否则会导致栈溢出。
1. 示例:计算阶乘
int factorial(int n) { if (n == 0) { // 终止条件 return 1; } else { return n * factorial(n - 1); // 递归调用 } } int main() { int result = factorial(5); // 计算5! = 120 cout << result << endl; return 0; }
2. 示例:斐波那契数列
int fibonacci(int n) { if (n <= 1) { // 终止条件 return n; } else { return fibonacci(n - 1) + fibonacci(n - 2); } }
八、常见错误和调试技巧
1. 常见错误
- 忘记声明函数:在调用前未声明函数,会导致编译错误。
- 参数类型不匹配:如函数要求
int
参数,却传入double
。 - 返回值类型错误:函数声明为
int
,但未返回整数。
2. 调试技巧
- 打印中间结果:在函数中使用
cout
输出变量值,检查逻辑是否正确。 - 使用断点:在IDE中设置断点,逐行调试观察变量变化。
九、综合示例:统计字符串中特定字符的出现次数
#include <iostream> #include <string> using namespace std; // 函数声明 int countChar(string str, char target); int main() { string text = "Hello, World!"; char target = 'l'; int count = countChar(text, target); // 调用函数 cout << "Character '" << target << "' appears " << count << " times." << endl; return 0; } // 函数定义:统计字符出现次数 int countChar(string str, char target) { int count = 0; for (char c : str) { // 遍历字符串 if (c == target) { count++; } } return count; // 返回统计结果 }
十、练习题
- 编写函数
max(int a, int b)
,返回两个整数中的较大值。 - 编写函数
swap(int& x, int& y)
,交换两个整数的值。 - 编写递归函数
sum(int n)
,计算1到n的和。
通过以上步骤,你可以逐步掌握C++函数的基本概念和使用方法。建议多练习,尝试将复杂问题分解为多个函数,提高代码的可读性和可维护性。
- 1