(4) 函数与模块化程序设计

时间:2024-10-30 11:57:44

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函数内对xy的交换操作不会影响main函数中的num1num2

从函数返回值
  • 函数通过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;
}

但要注意全局变量在多文件使用中的潜在问题,如命名冲突和意外修改等,尽量减少全局变量的使用,遵循模块化设计原则。

相关文章