1. 函数的定义、传值与返回值
函数的定义
- 在 C 语言中,函数由函数头和函数体组成。函数头包括函数返回类型、函数名和参数列表(可以为空)。函数体包含在一对花括号内,是实现函数功能的语句块。
- 以下是一个简单函数的示例,计算两个整数的和:
// 函数返回类型为 int,函数名为 add,参数为两个 int 型变量 a 和 b
int add(int a, int b) {
return a + b;
}
向函数传递值
-
值传递方式
C 语言中参数传递默认是值传递。在值传递中,实参的值被复制一份传递给形参。形参和实参在内存中占据不同的空间,对形参的修改不会影响实参。例如:
#include <stdio.h>
// 函数定义,这里的参数是值传递
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
printf("在 swap 函数内:x = %d, y = %d\n", x, y);
}
int main() {
int num1 = 5, num2 = 10;
printf("在 main 函数交换前:num1 = %d, num2 = %d\n", num1, num2);
swap(num1, num2);
printf("在 main 函数交换后:num1 = %d, num2 = %d\n", num1, num2);
return 0;
}
在这个例子中,swap
函数内对x
和y
的交换操作不会影响main
函数中的num1
和num2
。
从函数返回值
- 函数通过
return
语句返回值。返回值的类型必须与函数定义的返回类型一致(或者可以隐式转换为函数返回类型)。如果函数不需要返回值,返回类型应定义为void
。例如:
// 返回最大值的函数
int max(int a, int b) {
return (a > b)? a : b;
}
在main
函数或其他调用该函数的地方,可以接收并使用这个返回值:
int main() {
int num3 = 7, num4 = 9;
int result = max(num3, num4);
printf("最大值是:%d\n", result);
return 0;
}
2. 函数在程序设计中的使用与递归程序
函数在程序设计中的使用
-
函数的复用性
可以将一些常用的功能封装成函数,提高代码的复用性。例如,编写一个函数用于计算一个整数数组的平均值:
float average(int array[], int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += array[i];
}
return (float)sum / size;
}
在不同的地方,如果需要计算数组平均值,都可以调用这个函数。
递归程序
- 递归是指一个函数在其函数体内部调用自身的编程技巧。一个经典的递归例子是计算阶乘:
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
在这个factorial
函数中,当n
大于1时,函数通过return n * factorial(n - 1)
不断调用自身,直到n
等于0或1。递归需要有一个终止条件(在这个例子中是n == 0 || n == 1
),否则会导致无限递归。
3. 全局变量与局部变量、变量的作用域与生存期、存储方式的区别
全局变量与局部变量
-
全局变量
全局变量在函数外部定义,在整个程序中都可以访问(在同一源文件内,或者通过extern
关键字在其他源文件中访问)。例如:
int global_variable = 10; // 全局变量
void function1() {
printf("在 function1 中访问全局变量:%d\n", global_variable);
}
int main() {
function1();
printf("在 main 中访问全局变量:%d\n", global_variable);
return 0;
}
-
局部变量
局部变量在函数内部定义,其作用域仅限于该函数内部。例如:
void function2() {
int local_variable = 20; // 局部变量
printf("在 function2 中局部变量的值:%d\n", local_variable);
}
int main() {
function2();
// 这里不能访问 local_variable,因为它的作用域在 function2 内
return 0;
}
变量的作用域与生存期
-
作用域
- 全局变量的作用域从定义处开始到整个源文件结束(可通过
extern
扩展到其他文件)。 - 局部变量的作用域仅限于定义它的函数块内。例如在嵌套函数中:
- 全局变量的作用域从定义处开始到整个源文件结束(可通过
void outer_function() {
int outer_variable = 30;
void inner_function() {
int inner_variable = 40;
printf("在 inner_function 中:outer_variable = %d, inner_variable = %d\n", outer_variable, inner_variable);
}
inner_function();
// 这里不能访问 inner_variable
printf("在 outer_function 中:outer_variable = %d\n", outer_variable);
}
-
生存期
- 全局变量在程序开始执行时创建,在程序结束时销毁。
- 局部变量在函数被调用时创建,函数执行结束时销毁。对于静态局部变量(后面会讲到)则有所不同。
变量的动态与静态存储方式
-
动态存储方式(自动变量 - auto)
局部变量通常是自动变量,存储在栈中。每次函数调用时,自动变量被分配内存空间,函数结束时释放。例如前面例子中的普通局部变量。 -
静态存储方式(静态变量 - static)
- 静态局部变量在函数内定义,但它在程序的整个运行期间都存在,其值在多次函数调用之间保持不变。例如:
void counter_function() {
static int count = 0;
count++;
printf("count 的值:%d\n", count);
}
int main() {
counter_function();
counter_function();
return 0;
}
在这个例子中,count
是静态局部变量,每次调用counter_function
函数,count
的值都会在上次的基础上加1。
- 静态全局变量限制了该变量的作用域仅在定义它的源文件内,不能被其他源文件访问。它在程序开始时创建,程序结束时销毁。
4. 模块化程序设计的原则与思想、多个程序文件中函数的关系
模块化程序设计原则与思想
-
高内聚低耦合
高内聚意味着每个模块(函数或一组相关函数)应该有一个明确的、单一的功能。例如,一个函数专门用于字符串处理,另一个函数专门用于数学计算。低耦合要求模块之间的相互依赖尽量少,这样修改一个模块不会对其他模块产生过多的影响。 -
信息隐藏
模块内部的数据和实现细节应该对其他模块隐藏,只通过定义良好的接口(函数参数和返回值)与其他模块交互。例如,一个模块内部使用的数组或局部变量不应该被其他模块直接访问,其他模块只能通过该模块提供的函数来获取或修改相关信息。
多个程序文件中函数的关系
-
函数声明与定义分离
在 C 语言中,可以将函数的声明放在头文件(.h
文件)中,函数的定义放在源文件(.c
文件)中。例如,创建一个math_functions.h
头文件:
#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H
// 函数声明
int add(int a, int b);
int multiply(int a, int b);
#endif
然后在math_functions.c
源文件中实现这些函数:
#include "math_functions.h"
// 函数定义
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
-
在其他文件中使用函数
在另一个源文件(如main.c
)中,如果要使用math_functions.h
中声明的函数,可以包含头文件:
#include <stdio.h>
#include "math_functions.h"
int main() {
int result1 = add(3, 5);
int result2 = multiply(2, 4);
printf("3 + 5 = %d, 2 * 4 = %d\n", result1, result2);
return 0;
}
-
全局变量在多文件中的处理
如果要在多个文件中使用全局变量,可以在一个源文件中定义全局变量,在其他需要使用的源文件中通过extern
关键字声明该全局变量。例如,在global_variable.c
中定义全局变量:
int global_data = 100;
在main.c
中使用:
#include <stdio.h>
extern int global_data;
int main() {
printf("全局变量的值:%d\n", global_data);
return 0;
}
但要注意全局变量在多文件使用中的潜在问题,如命名冲突和意外修改等,尽量减少全局变量的使用,遵循模块化设计原则。