前言
继上一篇 深入理解C语言之函数 的文章推出后,应学弟学妹们的请求,继续推出这篇函数的文章。
掌握一门知识从来都不是那么容易的,只有从最基本的概念学起,然后经过不断实践、反思和总结,最后达到能教给别人的程度,才能算得上初步的掌握了知识点。
操千曲而后晓声,观千剑而后识器。虐它千百遍方能通晓其真意。
一、基本概念
1.1、定义
函数是C语言中实现模块化编程的基本单位。一个函数由函数头和函数体组成。
- 函数头:
- 返回类型:指定函数返回值的数据类型。
- 函数名:标识函数的名字。
- 参数列表:传递给函数的变量列表,可以为空。
- 函数体:
- 包含实际执行的
代码块,可以有多条语句。 - 可以使用
return语句返回值。
- 包含实际执行的
1.2、语法
返回类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...) {
// 函数体
// 可以有多条语句
// 可以使用 return 语句返回值
}
二、函数的类型
2.1、无参数、无返回值
// 定义一个无参数、无返回值的函数
void printHello() {
printf("Hello, World!\n");
}
2.2、带参数、无返回值
// 定义一个带参数、无返回值的函数
void printNumber(int a) {
printf("%d\n", a);
}
2.3、无参数、有返回值
// 定义一个无参数、有返回值的函数
int getNumber() {
return 4; // 返回一个固定的数
}
2.4、有参数、有返回值
// 定义一个带参数、有返回值的函数
int add(int a) {
int b = 10;
return a + b;
}
2.5、有多个参数、无返回值
// 定义一个带有多个参数、有返回值的函数
void calculateAverage(double a, double b, double c) {
double c = (a + b + c) / 3.0;
printf("Average: %.2f\n", average);
}
2.6、有多个参数、有返回值
// 定义一个带有多个参数、有返回值的函数
double calculateAverage(double a, double b, double c) {
return (a + b + c) / 3.0;
}
三、函数的声明及调用
在调用函数之前,必须先声明或定义该函数。如果函数定义在 main 函数之后,需要在 main 函数之前进行函数声明。
通过函数名加上括号来调用函数,如果函数有参数,则需要在括号内传入相应的参数。
3.1、语法
返回类型函数名(参数类型1参数名1, 参数类型2 参数名2, ...);
3.2、声明及调用
#include <stdio.h>
// 函数声明的语法结构
// 返回类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...);
// 函数声明
int add(int a, int b);
int main() {
int result = add(5, 3);
printf("Result: %d\n", result);
return 0;
}
// 函数定义
int add(int a, int b) {
return a + b;
}
四、参数传递与作用域
C语言支持两种参数传递方式:值传递和地址传递。- 局部变量:在
函数内部声明的变量,其作用域仅限于该函数。 - 全局变量:在
函数之外声明的变量,可以在整个文件中访问。
4.1、值传递
传递的是参数的副本,函数内部对参数的修改不会影响到调用者。
示例说明:
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main(void) {
int x = 10;
int y = 20;
printf("Before swap: x = %d, y = %d\n", x, y);
swap(x, y);
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
输出:
Before swap: x = 10, y = 20
After swap: x = 10, y = 20
4.2、地址传递
传递的是参数的地址,函数内部可以通过指针修改调用者的实际参数。
示例说明:
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int x = 10;
int y = 20;
printf("Before swap: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
输出:
Before swap: x = 10, y = 20
After swap: x = 20, y = 10
五、递归及递归函数
5.1、概述
- 递归:
- 是一种解决计算问题的方法,其中解决方案
取决于同一类问题的更小子集。
- 是一种解决计算问题的方法,其中解决方案
- 递归函数:
- 是指
函数调用自身的函数。递归函数必须有一个明确的终止条件,否则会导致无限递归。
- 是指
- 详细说明:
- 若每个函数对应一种解决方案, 自己调用自己意味着
解决方案是一致的(有规律的)。 - 每次调用,函数处理的数据会较上次
缩减(子集),而且最后会缩减至无需递归。 内层函数调用(子集处理)完成,外层函数才能算调用完成。- 深入最里层叫做
递 - 从最里层出来叫做
归 - 在递的过程中,外层函数内的
局部变量(以及方法参数)并未消失,归的时候可以用到。
- 若每个函数对应一种解决方案, 自己调用自己意味着
5.2、代码示例
#include <stdio.h>
// 定义一个递归函数
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main() {
int num = 5;
printf("Factorial of %d is %d\n", num, factorial(num));
return 0;
}
//详细执行流程说明
//1.初始执行
int factorial(int 5) {
if (n == 0 || n == 1) {
return 1;
} else {
//2.第一次递归调用
return 5*factorial(int 4) {
if (n == 0 || n == 1) {
return 1;
} else {
//3.第二次递归调用
return 4*factorial(int 3) {
if (n == 0 || n == 1) {
return 1;
} else {
//4.第三次递归调用
return 3*factorial(int 2) {
if (n == 0 || n == 1) {
return 1;
} else {
//5.第四次递归调用
return 2*factorial(int 1) {
if (n == 0 || n == 1) {
return 1;
} else {
return n* factorial(n-1);
}
}
}
}
}
}
}
}
}
}
5.3、执行流程
- 1、初始调用:
factorial(5)
- 2、第一次递归调用:
return 5 * factorial(4)
- 3、第二次递归调用:
return 4 * factorial(3)
- 4、第三次递归调用:
return 3 * factorial(2)
- 5、第四次递归调用:
return 2 * factorial(1)
- 6、基本终止条件:
return 1
-
7、回溯计算:
-
factorial(2)返回 2 * 1 = 2。 -
factorial(3)返回 3 * 2 = 6。 -
factorial(4)返回 4 * 6 = 24。 -
factorial(5)返回 5 * 24 = 120。 -
8、最终输出:
-
Factorial of 5 is 120
5.4、小结
- 递归函数:
factorial函数通过递归调用自身来计算阶乘。 - 终止条件:当
n为0或1时,递归终止。 - 回溯计算:每次递归调用的结果被用来计算上一层的值,直到最初的调用完成。
六、回调函数
回调函数是一种常见的编程模式,它允许你将一个函数作为参数传递给另一个函数,并在适当的时候调用这个函数。回调函数通常用于事件处理、异步操作和通用算法中。
实现步骤:
- 声明:确定回调函数的
签名(返回类型和参数列表)。 - 编写:实现具体的回调逻辑。
- 传递:将回调函数的
地址作为参数传递给另一个函数。 - 调用:在
适当的时候调用传递进来的回调函数
示例代码:
#include <stdio.h>
// 1、定义回调函数
typedef void (*Callback)(int);
// 2、实现具体的回调函数
void callbackFunction(int value) {
printf("value: %d\n", value);
}
// 3、定义一个接受回调函数的函数
void performOperation(Callback cb, int value) {
// 执行一些操作
printf("other operation...\n");
// 4、调用回调函数
if (cb != NULL) {
cb(value);
}
}
int main() {
// 传递回调函数并调用
performOperation(callbackFunction, 42);
return 0;
}
输出:
other operation...
value: 42
七、总结
C语言中的函数是实现模块化编程的关键工具,通过函数可以将代码组织成可重用的模块,提高代码的可读性、可维护性和开发效率。熟练掌握函数的定义、声明、参数传递、返回值、递归等基本概念至关重要,能为我们今后的搬砖工作打下坚实的基础。
码字不易,记得 关注 + 点赞 + 收藏 + 评论