本篇核心知识:函数基础、参数传递、函数重载、内联函数、函数指针、匿名函数、多文件编程、递归
一、函数基础(定义 / 调用 / 声明)
概念
函数是完成特定功能的代码块,可重复调用,提高代码复用性与可读性。
特性
-
定义格式:
返回值类型 函数名(形参列表) { 函数体(返回值) }-
返回值:函数执行结果,
void表示无返回值 -
形参:定义时的占位参数,不可在定义时给默认参数;实参:调用时传入的真实值
-
函数可以不含形参列表,即无参函数
-
-
函数声明:必须调用前声明,格式
返回值类型 函数名(形参列表);,允许定义后置-
默认参数:仅写在声明中,从右往左赋值,不可重复定义
例如:int fun(int,int=10) //带默认值的参数必须放在形参列表靠右位置
-
-
调用流程:
-
程序执行到调用处,转入被调函数
-
为形参分配临时内存,实参从左到右初始化形参
-
执行函数体,
return带回结果并结束函数 -
回到主调函数继续执行,释放形参内存
-
-
全局变量与局部变量 :局部变量可以隐藏全局变量,在有同名全局变量和局部变量的情形时,可以用
作用域解析运算符 ::提供对全局变量的访问。int a = 100; // 全局变量a void test() { int a = 20; // 局部变量隐藏全局变量 cout << a << endl; // 输出20,访问局部 cout << ::a << endl; // 输出100,:: 访问全局 } -
自定义函数内static定义的参数,不会随着多次调用被重新赋值
int fac(int n){
static int f=1; //static定义的int变量f,类似于函数范围内的全局变量
f=f*n;
return f;
}
main(){
int i;
for(i=1;i<=5;i++)
printf("%d!=%d\n",i,fac(i));//输出1到5的阶乘(1!=1\n 2!=2\n 3!=6\n...... 5!=120\n)
}
代码示例
// 函数声明(含默认参数)
int add(int a, int b = 0);
// 函数定义
int add(int a, int b) {
return a + b;
}
// 函数调用
int res = add(5); // b取默认值0,结果5
二、参数传递(三种方式)
概念
实参向形参传递数据的规则,决定函数内操作是否影响外部变量。
特性
1. 值传递(默认)
-
特点:传递实参副本,修改形参不影响原变量
-
适用:仅使用值、无需修改原数据
2. 地址传递(传指针)
-
特点:传递变量地址,通过指针可修改原变量值
-
适用:需修改外部变量、传递大数据
3. 引用传递(C++ 独有)
-
概念:引用是变量别名,同一块内存空间
-
特点:修改引用即改原变量,无需解引用
-
定义:
int &别名 = 原变量;,绑定后不可更改
4. 数组传参
-
数组名传参自动退化为指针,丢失长度,需额外传长度参数
-
函数内修改数组元素会影响外部原数组
代码示例
// 值传递
void swap1(int a, int b) {
int t = a; a = b; b = t;
}
// 地址传递
void swap2(int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
// 引用传递
void swap3(int &a, int &b) {
int t = a; a = b; b = t;
}
// 数组传参
void printArr(int arr[], int len) {
for(int i=0; i<len; i++) cout << arr[i] << " ";
}
相似概念比较:值传递 vs 地址传递 vs 引用传递
-
值传递:副本隔离,安全不影响原值。
-
地址传递:通过指针改原值,需解引用。
-
引用传递:别名直接改原值,语法简洁(C++)。
三、函数重载(C++)
概念
同一作用域内,同名函数、参数列表不同,实现多态调用。
特性
-
区分依据:参数个数 / 类型 / 顺序 ,返回值不参与区分
-
调用规则:按实参类型精确匹配
-
易错点:默认参数 + 重载易引发歧义,需避免
代码示例
// 重载函数
int calc(int a) { return a * 2; }
int calc(int a, int b) { return a + b; }
double calc(double a) { return a * 3; }
// 调用匹配
cout << calc(5) << endl; // 调用int calc(int)
cout << calc(2,3) << endl; // 调用int calc(int,int)
四、内联函数(inline)
概念
C++中用inline修饰的函数,编译时直接展开函数体,减少调用开销。
特性
-
关键字:
inline,声明 / 定义时均可加 -
原理:内存膨胀,空间换时间,避免函数跳转、栈帧创建开销
-
适用场景:短小、频繁调用的函数
-
限制:复杂函数(递归、循环多)不宜内联
代码示例
// 内联函数
inline int square(int x) {
return x * x;
}
// 调用时直接展开为x*x,无函数跳转
int s = square(4);
五、函数指针
概念
指向函数的指针,存储函数入口地址,可间接调用函数。
特性
-
定义格式:
返回值类型 (*指针名)(参数类型列表); -
调用方式:
指针名(实参)或(*指针名)(实参) -
用途:回调函数、多态实现、函数数组
代码示例
// 目标函数
int max(int a, int b) { return a > b ? a : b; }
// 定义函数指针
int (*pFun)(int, int) = max;
// 调用函数
cout << pFun(3,5) << endl; // 输出5
六、匿名函数(lambda表达式,C++11+)
概念
无需命名的临时函数,用于简单功能、捕获外部变量。
(禁止在一个函数内定义另一个函数,因此在一个函数内可以通过匿名函数定义新的函数)
特性
-
格式:
[捕获方式](参数)->返回值{函数体} -
捕获方式:
-
[变量]:值捕获(只读) -
[&变量]:引用捕获(可修改) -
[=]:值捕获所有外部变量(只读) -
[&]:引用捕获所有外部变量(可修改)
-
代码示例
int main(){
int x = 10;
// 匿名函数:捕获x,传入a,输出x+a
auto add = [x](int a) { return x + a; };
cout << add(5) << endl; // 输出10 + 5
}
七、多文件编程
概念
将代码拆分到多个文件,便于维护、复用,由头文件(.h)和源文件(.cpp)组成。
特性
-
头文件(.h) :存放函数声明、宏、全局变量声明;用
#pragma once防止重复定义 -
源文件(.cpp):存放函数实现、全局变量定义;包含对应头文件
-
规则 :全局变量仅定义一次,头文件只声明、不定义
代码示例
// 头文件:fun.h
#pragma once
int add(int a, int b);
// 源文件:fun.cpp
#include "fun.h"
int add(int a, int b) {
return a + b;
}
// 主文件:main.cpp
#include "fun.h"
int main() {
cout << add(1,2) << endl;
return 0;
}
八、递归
概念
函数直接或间接调用自身,解决重复性、分治类问题。
特性
-
两大要素:
-
递归出口:结束条件,避免无限递归
-
递归调用:向出口靠近,逐步简化问题
-
-
执行过程:层层深入调用,满足出口后逐层返回
-
适用场景:阶乘、斐波那契数列、扫雷翻开格子等
代码示例
// 递归求阶乘
int factorial(int n) {
if(n == 1) return 1; // 递归出口
return n * factorial(n-1); // 递归调用
}
// 调用
cout << factorial(5) << endl; // 输出120