新手注意:代码部分是用AI(豆包)生成的,所以写成了依托达芬,请见谅,别被误导了!!!
前言:为什么需要自定义函数?
在前一篇中,我们学会了调用系统自带的函数(比如 sort 排序、sqrt 求平方根),不用自己写复杂逻辑。但实际编程中,很多需求是系统函数覆盖不到的 —— 比如 “计算一个学生的总分”“判断一个数是否为质数”“打印指定格式的分隔线”,这些重复出现的逻辑如果每次都写一遍,代码会又长又难维护。
这时候就需要 “自定义函数”:把重复的逻辑封装成一个 “自己的工具”,像调用系统函数一样,用一句代码就能重复使用。比如把 “判断质数” 的逻辑写成函数 is_prime (n),之后不管是判断 17、23 还是 1009,直接调用 is_prime (17) 就行,不用再写一遍判断逻辑。
简单说,系统函数是别人做好的工具,自定义函数是自己做的专属工具,学会它能让你的代码更简洁、更易复用、更易调试。
一、先搞懂:自定义函数的核心结构
自定义函数就像 “一个有名字的代码模块”,有固定的格式,必须包含 “函数头” 和 “函数体”,缺一不可。我们先看一个最简单的例子:计算两个整数的和。
// 自定义函数:计算两个int类型的和 int add(int a, int b) { // 函数头 int result = a + b; // 函数体:具体逻辑 return result; // 返回结果(和的类型与函数返回值类型一致) }拆解函数的 4 个核心部分(新手必记)
- 返回值类型:函数执行后要返回的数据类型(比如上面的 int,表示返回整数)。如果函数不需要返回值,用void表示(后面会讲)。
- 函数名:自己起的名字(比如 add),遵循 “见名知义” 原则,最好能一眼看出函数功能(比如 is_prime 表示 “是否为质数”,print_line 表示 “打印分隔线”)。
- 参数列表:函数需要的 “输入数据”,格式是类型 参数名,多个参数用逗号分隔(比如 add 的 int a, int b)。参数就像函数的 “原材料”,调用时必须传入对应类型的值。
- 函数体:用 {} 包裹的具体逻辑,包括变量定义、计算、判断等。如果函数有返回值,必须用return 结果;语句返回(结果类型要和返回值类型匹配)。
新手易混点:函数声明 vs 函数定义
如果函数定义在main函数后面,编译器会找不到函数(因为 C++ 是从上到下编译的),这时候需要在main前加 “函数声明”—— 告诉编译器 “有这个函数,具体实现后面再写”。
格式:返回值类型 函数名(参数类型列表);(注意末尾有分号)
示例:
#include namespace std; // 函数声明(告诉编译器有一个add函数) int add(int, int); // 参数名可以省略,只写类型 int main() { int x = 5, y = 3; int sum = add(x, y); // 调用函数,传入x和y的值 cout <+3=" << sum << endl; // 输出:5+3=8 return 0; } // 函数定义(具体实现,要和声明的格式一致) int add(int a, int b) { return a + b; // 简化写法:直接返回结果,不用临时变量 }二、3 类常用自定义函数(实战案例 + 代码)
根据返回值和参数的不同,新手最常用的自定义函数有 3 类,每类都配 “可直接运行的代码”,复制就能练。
1. 有参数、有返回值(最常用)
功能:需要输入数据,执行后返回结果(比如计算、判断、查找)。
案例 1:判断一个数是否为质数(返回 bool 类型)
#include <iostream> #include <cmath> // 用到sqrt函数 using namespace std; // 函数声明:判断n是否为质数,是返回true,否返回false bool is_prime(int n); int main() { int num; cout << "请输入一个正整数:"; cin >> num; if (is_prime(num)) { cout << num << "是质数" <; } else { cout << num << "不是质数" <; } return 0; } // 函数定义:判断质数的逻辑 bool is_prime(int n) { if (n ; // 1及以下不是质数 if (n == 2) return true; // 2是唯一的偶数质数 if (n % 2 == 0) return false; // 偶数(除2外)不是质数 // 只需判断到sqrt(n),优化效率 for (int i = 3; i i += 2) { if (n % i == 0) return false; // 能被整除,不是质数 } return true; // 遍历结束没找到除数,是质数 }运行结果:
请输入一个正整数:17 17是质数案例 2:计算 n 的阶乘(n! = 1×2×...×n)
#include > using namespace std; int factorial(int n); // 函数声明 int main() { int n; cout <非负整数:"; cin >> n; if (n 0) { cout <负数" < return 1; // 异常退出 } cout < <:" <) < return 0; } // 函数定义:计算阶乘 int factorial(int n) { int res = 1; for (int i = 1; i res *= i; } return res; }运行结果:
请输入一个非负整数:5 5的阶乘是:1202. 有参数、无返回值(void 类型)
功能:需要输入数据,执行一个操作(比如打印、修改数组),不需要返回结果(用void表示返回值类型)。
案例:打印指定长度和字符的分隔线
#include std; // 函数声明:打印分隔线(length:长度,ch:字符) void print_line(int length, char ch); int main() { cout <内容" < print_line(20, '-'); // 调用函数:打印20个'-' cout < <_line(15, '*'); // 调用函数:打印15个'*' return 0; } // 函数定义:打印分隔线 void print_line(int length, char ch) { for (int i = 0; i < length; i++) { cout < } cout << endl; // 换行 }运行结果:
第一部分内容 -------------------- 第二部分内容 ***************3. 无参数、有返回值
功能:不需要输入数据,执行后返回一个固定或动态的结果(比如获取随机数、获取当前时间)。
案例:生成 1-100 的随机数
#include #include // rand()函数 #include time()函数(设置随机数种子) using namespace std; // 函数声明:返回1-100的随机数 int get_random(); int main() { // 设置随机数种子(确保每次运行结果不同) srand((unsigned int)time(NULL)); cout <1-100的随机数:" <; for (int i = 0; i { cout <_random() < } cout << endl; return 0; } // 函数定义:生成1-100的随机数 int get_random() { // rand()返回0~RAND_MAX的随机数,取模100得0~99,加1得1~100 return rand() % 100 + 1; }运行结果(每次不同):
生成5个1-100的随机数: 45 68 23 90 12三、关键知识点:参数传递的 2 种方式(新手必懂)
调用函数时,参数传递有两种核心方式:值传递和引用传递,新手容易混淆,直接看对比表 + 案例更清晰。
传递方式 | 核心特点 | 适用场景 |
值传递 | 函数接收参数的 “副本”,修改副本不影响原变量 | 不需要修改原变量(比如计算、判断) |
引用传递 | 函数接收参数的 “内存地址”,修改会影响原变量 | 需要修改原变量(比如交换两个数、修改数组元素) |
1. 值传递(默认方式)
示例:试图交换两个数,但失败(因为修改的是副本)
#include namespace std; // 值传递:x和y是a和b的副本 void swap_value(int x, int y) { int temp = x; x = y; y = temp; cout <x=" << x < y=" << y <; // 函数内交换成功 } int main() { int a = 3, b = 5; cout <=" << a <=" << b < // 交换前a=3, b=5 swap_value(a, b); // 传入a和b的值(副本) cout <交换后a=" < << ", b=" < <交换后a=3, b=5(原变量未变) return 0; }运行结果:
交换前a=3, b=5 函数内x=5, y=3 交换后a=3, b=52. 引用传递(参数前加 &)
示例:成功交换两个数(修改的是原变量)
#include using namespace std; // 引用传递:x是a的别名,y是b的别名(指向同一内存) void swap_ref(int& x, int& y) { int temp = x; x = y; y = temp; } int main() { int a = 3, b = 5; cout <前a=" << a << ", b=" << b << endl; // 交换前a=3, b=5 swap_ref(a, b); // 传入a和b的引用 cout <交换后a=" < << ", b=" < <交换后a=5, b=3(原变量已变) return 0; }运行结果:
交换前a=3, b=5 交换后a=5, b=3新手记住:如果想让函数修改原变量,就用引用传递(参数前加 &);否则用值传递(默认)。
四、综合实战:用自定义函数实现 “学生成绩管理”
结合前一篇的系统函数和本篇的自定义函数,实现一个更完整的成绩管理工具,功能包括:
- 输入 n 名学生的成绩(自定义函数 input_scores);
- 计算平均分(自定义函数 calc_average);
- 找出最高分(自定义函数 find_max);
- 按降序排序(系统函数 sort);
- 输出结果(自定义函数 print_result)。
完整代码:
#include 函数 using namespace std; const int MAX_STUDENT = 100; // 最大学生数 // 函数声明 void input_scores(double scores[], int& n); // 输入成绩(引用传递n,因为要修改它) double calc_average(double scores[], int n); // 计算平均分 double find_max(double scores[], int n); // 找最高分 void print_result(double scores[], int n); // 输出结果 int main() { double scores[MAX_STUDENT]; int n; // 实际学生数 // 调用自定义函数,完成各功能 input_scores(scores, n); if (n == 0) { cout <输入成绩!" <; return 1; } print_result(scores, n); return 0; } // 函数定义1:输入成绩 void input_scores(double scores[], int& n) { cout <输入学生人数(不超过" < < cin >> n; if (n 1 || n > MAX_STUDENT) { n = 0; return; // 非法输入,返回0人 } cout << "请输入" << n <成绩:" < for (int i = 0; i < n; i++) { cout < < <"; cin >> scores[i]; } } // 函数定义2:计算平均分 double calc_average(double scores[], int n) { double total = 0; for (int i = 0; i < n; i++) { total += scores[i]; } return total / n; } // 函数定义3:找最高分 double find_max(double scores[], int n) { double max_score = scores[0]; for (int i = 1; i < n; i++) { if (scores[i] > max_score) { max_score = scores[i]; } } return max_score; } // 函数定义4:输出结果 void print_result(double scores[], int n) { // 调用系统函数sort,按降序排序 sort(scores, scores + n, greater>()); double average = calc_average(scores, n); double max_score = find_max(scores, n); cout <成绩统计结果 ===" << endl; cout << "降序排序后的成绩:"; for (int i = 0; i { cout <[i] < } cout << "\n最高分:" << max_score < < << "平均分:" << average << "分" << endl; }运行结果:
请输入学生人数(不超过100):5 请输入5名学生的成绩: 第1名学生成绩:85.5 第2名学生成绩:92.0 第3名学生成绩:78.5 第4名学生成绩:90.0 第5名学生成绩:88.0 === 成绩统计结果 === 降序排序后的成绩:92 90 88 85.5 78.5 最高分:92分 平均分:86.8分五、新手自定义函数的 4 个常见坑点与解决方案
- 函数声明和定义的格式不一致
- 错误现象:编译器报错 “conflicting declaration”(冲突声明);
- 例子:声明是int add(int a, double b),定义是int add(int x, int y)(参数类型不一致);
- 解决方案:声明和定义的 “返回值类型、函数名、参数类型 + 顺序” 必须完全一致。
- 返回值类型和 return 语句不匹配
- 错误现象:编译器报错 “return type mismatch”(返回类型不匹配);
- 例子:函数返回值类型是 int,却 return 3.14(double 类型);
- 解决方案:return 的结果类型必须和函数头的返回值类型一致,必要时用强制类型转换(比如return (int)3.14;)。
- 引用传递误用(修改了不该改的变量)
- 错误现象:原变量被函数意外修改;
- 原因:不需要