
课程目标
- 理解函数的概念和优势
- 掌握函数的定义、声明和调用
- 理解参数传递(值传递)的机制
- 理解返回值的意义和使用
- 初步了解递归的概念
- 学会将复杂问题模块化
第一部分:函数的基本概念(40分钟)
1.1 什么是函数?
生活比喻:
- 厨房电器:微波炉、烤箱 - 输入食材,输出熟食,我们不需要知道内部原理
- 快递员:把包裹(参数)交给快递员,他负责送到目的地(返回值)
- 工厂生产线:每个工人(函数)负责特定的工序
1.2 为什么需要函数?
没有函数的困境:
cpp
#include <iostream>
using namespace std;
int main() {
// 计算圆的面积(重复代码)
double radius1 = 5.0;
double area1 = 3.14159 * radius1 * radius1;
cout << "圆1的面积: " << area1 << endl;
double radius2 = 3.0;
double area2 = 3.14159 * radius2 * radius2;
cout << "圆2的面积: " << area2 << endl;
double radius3 = 7.0;
double area3 = 3.14159 * radius3 * radius3;
cout << "圆3的面积: " << area3 << endl;
return 0;
}
使用函数的便利:
cpp
#include <iostream>
using namespace std;
// 定义计算圆面积的函数
double calculateCircleArea(double radius) {
return 3.14159 * radius * radius;
}
int main() {
// 使用函数计算圆的面积
cout << "圆1的面积: " << calculateCircleArea(5.0) << endl;
cout << "圆2的面积: " << calculateCircleArea(3.0) << endl;
cout << "圆3的面积: " << calculateCircleArea(7.0) << endl;
return 0;
}
1.3 函数的优势
- 代码复用:避免重复编写相同代码
- 模块化:将复杂问题分解为小问题
- 可读性:函数名可以描述功能,代码更易理解
- 易于维护:修改功能只需修改一个地方
- 团队协作:不同程序员可以负责不同函数
第二部分:函数的定义和调用(60分钟)
2.1 函数的组成部分
函数定义语法:
cpp
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 如果返回类型不是void
}
2.2 无参数无返回值的函数
cpp
#include <iostream>
using namespace std;
// 函数定义:显示欢迎信息
void showWelcome() {
cout << "****************" << endl;
cout << "* 欢迎使用! *" << endl;
cout << "****************" << endl;
}
// 函数定义:显示菜单
void showMenu() {
cout << "\n=== 菜单 ===" << endl;
cout << "1. 开始游戏" << endl;
cout << "2. 设置" << endl;
cout << "3. 退出" << endl;
cout << "============" << endl;
}
int main() {
// 函数调用
showWelcome();
showMenu();
cout << "程序继续执行..." << endl;
// 可以多次调用同一个函数
showMenu();
return 0;
}
2.3 带参数无返回值的函数
cpp
#include <iostream>
using namespace std;
// 函数定义:显示指定次数的消息
void showMessage(string message, int times) {
for (int i = 0; i < times; i++) {
cout << message << endl;
}
}
// 函数定义:显示个人信息
void showPersonInfo(string name, int age, double height) {
cout << "\n=== 个人信息 ===" << endl;
cout << "姓名: " << name << endl;
cout << "年龄: " << age << "岁" << endl;
cout << "身高: " << height << "米" << endl;
}
// 函数定义:打印指定行数和列数的图案
void printPattern(char symbol, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << symbol << " ";
}
cout << endl;
}
}
int main() {
// 调用带参数的函数
showMessage("Hello, Function!", 3);
showPersonInfo("小明", 12, 1.65);
printPattern('*', 4, 6);
return 0;
}
2.4 带返回值的函数
cpp
#include <iostream>
using namespace std;
// 函数定义:计算两个数的和
int add(int a, int b) {
int result = a + b;
return result; // 返回计算结果
}
// 函数定义:判断一个数是否为偶数
bool isEven(int number) {
return number % 2 == 0; // 直接返回布尔表达式的结果
}
// 函数定义:计算阶乘
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
// 函数定义:获取成绩等级
char getGrade(int score) {
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 70) return 'C';
else if (score >= 60) return 'D';
else return 'E';
}
int main() {
// 使用带返回值的函数
int sum = add(5, 3);
cout << "5 + 3 = " << sum << endl;
// 直接在表达式中使用函数调用
cout << "10 + 15 = " << add(10, 15) << endl;
// 使用判断函数
int num = 7;
if (isEven(num)) {
cout << num << " 是偶数" << endl;
} else {
cout << num << " 是奇数" << endl;
}
// 使用计算函数
cout << "5的阶乘 = " << factorial(5) << endl;
// 使用等级函数
int score = 85;
cout << "成绩 " << score << " 的等级是: " << getGrade(score) << endl;
return 0;
}
第三部分:参数传递机制(50分钟)
3.1 值传递(Pass by Value)
值传递的特点:
- 函数接收参数的副本,不是原始变量
- 在函数内修改参数不会影响原始变量
- 就像复印文件,修改复印件不影响原件
cpp
#include <iostream>
using namespace std;
// 值传递示例
void modifyValue(int x) {
cout << "函数内修改前: x = " << x << endl;
x = x * 2; // 修改参数的值
cout << "函数内修改后: x = " << x << endl;
}
// 交换两个数的值(错误版本)
void swapWrong(int a, int b) {
int temp = a;
a = b;
b = temp;
cout << "函数内: a = " << a << ", b = " << b << endl;
}
// 计算矩形面积和周长
void calculateRectangle(double length, double width, double &area, double &perimeter) {
area = length * width;
perimeter = 2 * (length + width);
}
int main() {
// 值传递示例
int num = 5;
cout << "调用函数前: num = " << num << endl;
modifyValue(num);
cout << "调用函数后: num = " << num << endl;
cout << "注意:num的值没有改变!" << endl;
cout << "\n--- 交换函数测试 ---" << endl;
int x = 10, y = 20;
cout << "交换前: x = " << x << ", y = " << y << endl;
swapWrong(x, y);
cout << "交换后: x = " << x << ", y = " << y << endl;
cout << "注意:x和y的值没有交换!" << endl;
return 0;
}
3.2 多返回值问题
cpp
#include <iostream>
using namespace std;
// 方法1:使用多个函数(不推荐)
double calculateArea(double length, double width) {
return length * width;
}
double calculatePerimeter(double length, double width) {
return 2 * (length + width);
}
// 方法2:使用引用参数(后续课程详细讲解)
void calculateRectangle(double length, double width, double &area, double &perimeter) {
area = length * width;
perimeter = 2 * (length + width);
}
// 方法3:使用数组或结构体(后续课程学习)
int main() {
double len = 5.0, wid = 3.0;
// 方法1:调用多个函数
double area1 = calculateArea(len, wid);
double perimeter1 = calculatePerimeter(len, wid);
cout << "方法1 - 面积: " << area1 << ", 周长: " << perimeter1 << endl;
// 方法2:使用引用参数
double area2, perimeter2;
calculateRectangle(len, wid, area2, perimeter2);
cout << "方法2 - 面积: " << area2 << ", 周长: " << perimeter2 << endl;
return 0;
}
第四部分:函数声明和定义分离(30分钟)
4.1 为什么需要函数声明?
问题场景:
cpp
#include <iostream>
using namespace std;
int main() {
// 错误:函数在调用之后定义
int result = multiply(5, 3); // 编译错误!
cout << "结果: " << result << endl;
return 0;
}
// 函数定义在main之后
int multiply(int a, int b) {
return a * b;
}
4.2 函数声明(函数原型)
解决方案:函数声明 + 函数定义
cpp
#include <iostream>
using namespace std;
// 函数声明(函数原型)
int multiply(int a, int b);
void showInfo(string name, int age);
double calculateBMI(double weight, double height);
bool isPrime(int number);
int main() {
// 现在可以正确调用函数了
cout << "5 × 3 = " << multiply(5, 3) << endl;
showInfo("小明", 12);
double bmi = calculateBMI(45.0, 1.65);
cout << "BMI: " << bmi << endl;
int num = 17;
if (isPrime(num)) {
cout << num << " 是质数" << endl;
} else {
cout << num << " 不是质数" << endl;
}
return 0;
}
// 函数定义
int multiply(int a, int b) {
return a * b;
}
void showInfo(string name, int age) {
cout << "姓名: " << name << ", 年龄: " << age << endl;
}
double calculateBMI(double weight, double height) {
return weight / (height * height);
}
bool isPrime(int number) {
if (number <= 1) return false;
for (int i = 2; i * i <= number; i++) {
if (number % i == 0) return false;
}
return true;
}
4.3 多文件组织(了解概念)
cpp
// math_functions.h - 头文件(函数声明)
#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H
int add(int a, int b);
int multiply(int a, int b);
double divide(double a, double b);
#endif
// math_functions.cpp - 源文件(函数定义)
#include "math_functions.h"
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
double divide(double a, double b) {
if (b != 0) return a / b;
else return 0;
}
// main.cpp - 主程序
#include <iostream>
#include "math_functions.h"
using namespace std;
int main() {
cout << "5 + 3 = " << add(5, 3) << endl;
cout << "5 × 3 = " << multiply(5, 3) << endl;
cout << "10 ÷ 3 = " << divide(10, 3) << endl;
return 0;
}
第五部分:递归初步(50分钟)
5.1 什么是递归?
递归的概念:
- 函数直接或间接调用自身
- 像俄罗斯套娃,大娃娃里面有小娃娃
- 像镜子对着镜子,无限反射
生活比喻:
- 讲故事:"从前有座山,山里有座庙,庙里有个老和尚在讲故事:从前有座山..."
- 查字典:查一个词,解释中又有不认识的词,继续查...
5.2 递归的基本结构
递归三要素:
- 基准情况:递归结束的条件
- 递归调用:函数调用自身
- 向基准情况推进:每次调用都更接近结束条件
5.3 递归示例:阶乘计算
数学定义:
- 0! = 1(基准情况)
- n! = n × (n-1)!(递归关系)
cpp
#include <iostream>
using namespace std;
// 递归函数:计算阶乘
int factorial(int n) {
// 基准情况
if (n == 0 || n == 1) {
cout << "到达基准情况: factorial(" << n << ") = 1" << endl;
return 1;
}
// 递归调用
cout << "计算 factorial(" << n << ") = " << n << " × factorial(" << n-1 << ")" << endl;
int result = n * factorial(n - 1);
cout << "返回 factorial(" << n << ") = " << result << endl;
return result;
}
int main() {
int number = 5;
cout << "计算 " << number << " 的阶乘:" << endl;
int result = factorial(number);
cout << number << "! = " << result << endl;
return 0;
}
5.4 递归示例:斐波那契数列
数学定义:
- F(0) = 0
- F(1) = 1
- F(n) = F(n-1) + F(n-2)
cpp
#include <iostream>
using namespace std;
// 递归函数:计算斐波那契数列
int fibonacci(int n) {
// 基准情况
if (n == 0) return 0;
if (n == 1) return 1;
// 递归调用
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 显示斐波那契数列
void showFibonacci(int count) {
cout << "斐波那契数列前" << count << "项: ";
for (int i = 0; i < count; i++) {
cout << fibonacci(i) << " ";
}
cout << endl;
}
int main() {
showFibonacci(10);
// 计算单个斐波那契数
int n = 6;
cout << "斐波那契数列第" << n << "项: " << fibonacci(n) << endl;
return 0;
}
5.5 递归的优缺点
优点:
- 代码简洁,表达力强
- 适合解决分治问题
- 符合数学定义
缺点:
- 可能效率较低(重复计算)
- 可能栈溢出(递归深度太大)
- 可能难以理解
第六部分:综合应用示例(60分钟)
6.1 数学工具包
cpp
#include <iostream>
#include <cmath>
using namespace std;
// 函数声明
void showMenu();
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
int power(int base, int exponent);
int factorial(int n);
int gcd(int a, int b); // 最大公约数
bool isPrime(int number);
int main() {
int choice;
do {
showMenu();
cout << "请选择操作: ";
cin >> choice;
if (choice >= 1 && choice <= 4) {
int a, b;
cout << "请输入第一个数字: ";
cin >> a;
cout << "请输入第二个数字: ";
cin >> b;
switch (choice) {
case 1:
cout << a << " + " << b << " = " << add(a, b) << endl;
break;
case 2:
cout << a << " - " << b << " = " << subtract(a, b) << endl;
break;
case 3:
cout << a << " × " << b << " = " << multiply(a, b) << endl;
break;
case 4:
if (b != 0) {
cout << a << " ÷ " << b << " = " << divide(a, b) << endl;
} else {
cout << "错误:除数不能为0!" << endl;
}
break;
}
} else if (choice == 5) {
int base, exp;
cout << "请输入底数: ";
cin >> base;
cout << "请输入指数: ";
cin >> exp;
cout << base << "^" << exp << " = " << power(base, exp) << endl;
} else if (choice == 6) {
int n;
cout << "请输入要计算阶乘的数: ";
cin >> n;
if (n >= 0) {
cout << n << "! = " << factorial(n) << endl;
} else {
cout << "错误:阶乘只能计算非负整数!" << endl;
}
} else if (choice == 7) {
int a, b;
cout << "请输入第一个数: ";
cin >> a;
cout << "请输入第二个数: ";
cin >> b;
cout << a << "和" << b << "的最大公约数是: " << gcd(a, b) << endl;
} else if (choice == 8) {
int number;
cout << "请输入要检查的数: ";
cin >> number;
if (isPrime(number)) {
cout << number << " 是质数" << endl;
} else {
cout << number << " 不是质数" << endl;
}
} else if (choice != 0) {
cout << "无效选择!" << endl;
}
} while (choice != 0);
cout << "感谢使用数学工具包!" << endl;
return 0;
}
// 函数定义
void showMenu() {
cout << "\n=== 数学工具包 ===" << endl;
cout << "1. 加法" << endl;
cout << "2. 减法" << endl;
cout << "3. 乘法" << endl;
cout << "4. 除法" << endl;
cout << "5. 幂运算" << endl;
cout << "6. 阶乘" << endl;
cout << "7. 最大公约数" << endl;
cout << "8. 质数判断" << endl;
cout << "0. 退出" << endl;
}
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
double divide(int a, int b) { return static_cast<double>(a) / b; }
int power(int base, int exponent) {
int result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
int factorial(int n) {
if (n == 0 || n == 1) return 1;
return n * factorial(n - 1);
}
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
bool isPrime(int number) {
if (number <= 1) return false;
for (int i = 2; i * i <= number; i++) {
if (number % i == 0) return false;
}
return true;
}
6.2 图形绘制工具
cpp
#include <iostream>
using namespace std;
// 函数声明
void drawRectangle(int width, int height, char symbol);
void drawTriangle(int height, char symbol);
void drawDiamond(int size, char symbol);
void drawChristmasTree(int levels);
int main() {
int choice;
cout << "=== 图形绘制工具 ===" << endl;
// 绘制矩形
cout << "\n1. 绘制矩形:" << endl;
drawRectangle(8, 4, '*');
// 绘制三角形
cout << "\n2. 绘制三角形:" << endl;
drawTriangle(5, '#');
// 绘制菱形
cout << "\n3. 绘制菱形:" << endl;
drawDiamond(5, '+');
// 绘制圣诞树
cout << "\n4. 绘制圣诞树:" << endl;
drawChristmasTree(4);
return 0;
}
// 函数定义:绘制矩形
void drawRectangle(int width, int height, char symbol) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
cout << symbol;
}
cout << endl;
}
}
// 函数定义:绘制三角形
void drawTriangle(int height, char symbol) {
for (int i = 1; i <= height; i++) {
// 打印空格
for (int j = 1; j <= height - i; j++) {
cout << " ";
}
// 打印符号
for (int j = 1; j <= 2 * i - 1; j++) {
cout << symbol;
}
cout << endl;
}
}
// 函数定义:绘制菱形
void drawDiamond(int size, char symbol) {
// 上半部分
for (int i = 1; i <= size; i++) {
for (int j = 1; j <= size - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << symbol;
cout << endl;
}
// 下半部分
for (int i = size - 1; i >= 1; i--) {
for (int j = 1; j <= size - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << symbol;
cout << endl;
}
}
// 函数定义:绘制圣诞树
void drawChristmasTree(int levels) {
for (int level = 1; level <= levels; level++) {
int height = level + 1;
for (int i = 1; i <= height; i++) {
// 打印空格
for (int j = 1; j <= levels - i + 1; j++) {
cout << " ";
}
// 打印星号
for (int j = 1; j <= 2 * i - 1; j++) {
cout << "*";
}
cout << endl;
}
}
// 树干
for (int i = 0; i < 2; i++) {
for (int j = 1; j <= levels; j++) {
cout << " ";
}
cout << "|" << endl;
}
}
练习与作业
基础练习(必做)
练习1:数学函数库
创建以下数学函数:
square(int n)- 返回n的平方cube(int n)- 返回n的立方isEven(int n)- 判断n是否为偶数isPositive(int n)- 判断n是否为正数max(int a, int b)- 返回a和b中的较大值
练习2:温度转换器
编写温度转换函数:
celsiusToFahrenheit(double celsius)- 摄氏转华氏fahrenheitToCelsius(double fahrenheit)- 华氏转摄氏- 编写主程序让用户选择转换方向并输入温度
练习3:字符串处理函数
创建字符串处理函数:
stringLength(string str)- 返回字符串长度(不用内置函数)countVowels(string str)- 统计元音字母个数reverseString(string str)- 返回反转后的字符串
挑战练习(选做)
挑战1:递归深度探索
- 编写递归函数计算数字的各位数之和
- 编写递归函数判断字符串是否是回文
- 测试递归深度限制,找出你的计算机最多支持多深的递归
挑战2:函数组合应用
创建一个"数字分析器"程序,包含以下功能:
- 判断质数
- 计算所有因数
- 判断完美数(等于其所有真因数之和的数)
- 判断阿姆斯特朗数(各位数字立方和等于自身的数)
挑战3:模块化游戏
将之前学过的猜数字游戏重构为模块化程序:
generateRandomNumber()- 生成随机数getUserGuess()- 获取用户猜测giveHint(int guess, int target)- 给出提示playGame()- 游戏主逻辑
实验任务
任务1:函数调用栈实验
通过调试或输出语句跟踪以下递归函数的执行过程:
cpp
void countDown(int n) {
if (n < 0) return;
cout << "进入: countDown(" << n << ")" << endl;
countDown(n - 1);
cout << "离开: countDown(" << n << ")" << endl;
}
任务2:值传递验证
设计实验验证值传递机制:
cpp
void testValuePassing(int x) {
x = 100;
cout << "函数内: x = " << x << endl;
}
// 调用后检查原始变量是否改变
任务3:函数性能测试
比较递归和迭代版本的阶乘函数:
- 测试计算20!的时间
- 测试能计算的最大阶乘值
- 分析两种方法的优缺点
学习总结
今天学到了:
- ✅ 函数概念:模块化编程的基本单元
- ✅ 函数定义:返回类型、函数名、参数列表、函数体
- ✅ 函数调用:使用函数执行特定任务
- ✅ 参数传递:值传递机制和特点
- ✅ 返回值:函数执行结果的返回
- ✅ 函数声明:提前声明函数原型
- ✅ 递归初步:函数调用自身的编程技巧
关键技能:
- 模块化设计:将复杂问题分解为函数
- 接口设计:设计合理的函数参数和返回值
- 代码复用:通过函数避免重复代码
- 递归思维:用递归方式解决自相似问题
下一课预告:
下一节课我们将学习排序与查找算法,包括选择排序、冒泡排序、顺序查找和二分查找,这是算法学习的重要基础!