• C
  • C语言函数教程01

  • @ 2025-6-6 7:27:29

C语言函数详解

函数是C语言程序的基本组成单元,它可以将复杂任务分解为小模块,提高代码复用性和可维护性。本教程适合零基础学习者,通过示例和注释详细讲解函数的使用。

1. 函数的基本概念

函数是一段完成特定任务的独立代码块,有输入参数和返回值(可选)。类似于数学中的函数 y = f(x),C语言函数接收输入(参数),执行操作,返回结果。

函数的优点

  • 代码复用
  • 模块化设计
  • 便于调试和维护

2. 函数的定义与调用

2.1 函数定义的语法

返回类型 函数名(参数列表) {
    // 函数体(代码逻辑)
    return 返回值;  // 与返回类型匹配
}
  • 返回类型:函数返回值的数据类型(如 int, float, void 等)。
  • 函数名:自定义标识符,命名规则与变量相同。
  • 参数列表:输入参数的类型和名称,多个参数用逗号分隔。
  • 函数体:实现具体功能的代码块。
  • return语句:结束函数并返回值(返回类型为 void 时可省略)。

2.2 示例:定义一个简单的函数

// 定义一个函数:计算两数之和
int add(int a, int b) {  // 接收两个整数参数
    int sum = a + b;     // 计算和
    return sum;          // 返回结果
}

2.3 函数调用

定义后的函数需要被调用才能执行。调用时需提供参数(如果有),并可以接收返回值。

#include <stdio.h>

int main() {
    int result;
    // 调用add函数,传入参数5和3,并将返回值赋给result
    result = add(5, 3);  
    printf("5 + 3 = %d\n", result);  // 输出:5 + 3 = 8
    return 0;
}

3. 函数参数

3.1 形式参数(形参)与实际参数(实参)

  • 形参:函数定义时声明的参数,用于接收外部传入的值。
  • 实参:函数调用时传递给函数的实际值。
// 形参:a和b
int multiply(int a, int b) {  
    return a * b;
}

int main() {
    int x = 4, y = 5;
    // 实参:x和y(或直接用常量4和5)
    int result = multiply(x, y);  
    return 0;
}

3.2 参数传递方式

C语言通过值传递方式传递参数,即传递的是实参的副本,而非实参本身。因此,函数内部修改形参不会影响实参。

// 尝试交换两个数(错误示例)
void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    // 仅交换了形参a和b的副本,实参不受影响
}

int main() {
    int x = 10, y = 20;
    swap(x, y);  // 调用后x和y的值不变
    printf("x = %d, y = %d\n", x, y);  // 输出:x = 10, y = 20
    return 0;
}

4. 返回值与返回类型

4.1 返回类型

函数可以返回各种数据类型的值,如 int, float, char 等。如果不需要返回值,使用 void 类型。

// 返回浮点数的函数
float divide(float a, float b) {
    if (b != 0) {
        return a / b;
    } else {
        printf("Error: division by zero!\n");
        return 0.0;  // 错误处理
    }
}

// 无返回值的函数
void printHello() {
    printf("Hello, World!\n");
    // 无需return语句
}

4.2 return语句

  • 终止函数执行并返回值。
  • 返回值的类型必须与函数定义的返回类型一致。
  • 一个函数可以有多个return语句,但只能执行其中一个。
int max(int a, int b) {
    if (a > b) {
        return a;  // 条件满足时执行此return
    } else {
        return b;  // 条件不满足时执行此return
    }
}

5. 函数声明与头文件

5.1 函数声明

如果函数定义在调用之后,需要在调用前进行函数声明(原型声明)。声明告诉编译器函数的返回类型、名称和参数类型。

#include <stdio.h>

// 函数声明(原型)
int subtract(int a, int b);  // 声明但不实现

int main() {
    int result = subtract(10, 5);  // 调用在定义前
    printf("10 - 5 = %d\n", result);
    return 0;
}

// 函数定义(实现)
int subtract(int a, int b) {
    return a - b;
}

5.2 头文件的使用

将函数声明放在头文件(.h)中,函数定义放在源文件(.c)中,可以提高代码组织性。

示例:

  1. 创建 math_operations.h 头文件:

    // math_operations.h
    #ifndef MATH_OPERATIONS_H
    #define MATH_OPERATIONS_H
    
    // 函数声明
    int add(int a, int b);
    int subtract(int a, int b);
    
    #endif
    
  2. 创建 math_operations.c 源文件:

    // math_operations.c
    #include "math_operations.h"
    
    // 函数定义
    int add(int a, int b) {
        return a + b;
    }
    
    int subtract(int a, int b) {
        return a - b;
    }
    
  3. 在主程序中使用:

    // main.c
    #include <stdio.h>
    #include "math_operations.h"  // 包含自定义头文件
    
    int main() {
        int sum = add(3, 4);
        int diff = subtract(10, 5);
        printf("Sum: %d, Difference: %d\n", sum, diff);
        return 0;
    }
    

6. 递归函数

递归是指函数调用自身的编程技术。递归函数通常包含两个部分:

  • 基线条件(终止条件):停止递归的条件。
  • 递归条件:函数调用自身的条件。

示例:计算阶乘

// 递归计算n的阶乘
int factorial(int n) {
    if (n == 0 || n == 1) {  // 基线条件
        return 1;
    } else {  // 递归条件
        return n * factorial(n - 1);  // 调用自身
    }
}

递归执行过程(以 factorial(3) 为例):

factorial(3) → 3 * factorial(2)
                → 2 * factorial(1)
                    → 1 (基线条件,返回1)
                → 2 * 1 = 2
            → 3 * 2 = 6

7. 变量的作用域

变量的作用域决定了它的可见性和生命周期。在函数中,变量分为:

  • 局部变量:在函数内部定义,只能在函数内访问,函数结束后销毁。
  • 全局变量:在所有函数外部定义,整个程序都能访问,生命周期为程序运行期间。
#include <stdio.h>

int global = 10;  // 全局变量

void test() {
    int local = 20;  // 局部变量
    printf("Global: %d, Local: %d\n", global, local);
}

int main() {
    test();  // 输出:Global: 10, Local: 20
    printf("Global: %d\n", global);  // 可以访问全局变量
    // printf("Local: %d\n", local);  // 错误:无法访问局部变量
    return 0;
}

8. 实践案例:计算数组平均值

#include <stdio.h>

// 计算数组元素的平均值
float average(int arr[], int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += arr[i];
    }
    return (float)sum / size;  // 转换为浮点数避免整数除法
}

int main() {
    int numbers[] = {10, 20, 30, 40, 50};
    int n = sizeof(numbers) / sizeof(numbers[0]);  // 计算数组长度
    float avg = average(numbers, n);
    printf("Average: %.2f\n", avg);  // 输出:Average: 30.00
    return 0;
}

9. 常见错误与注意事项

  1. 忘记声明或定义函数:编译器会报错“隐式声明”。
  2. 返回类型不匹配:确保return语句的类型与函数声明一致。
  3. 无限递归:忘记基线条件会导致栈溢出。
  4. 修改值传递的参数:函数内无法直接修改实参(需用指针,后续教程介绍)。

10. 练习题目

  1. 编写函数 isPrime(int n),判断一个数是否为素数。
  2. 编写函数 reverse(int n),反转一个整数(例如:输入123,输出321)。
  3. 编写函数 maxElement(int arr[], int size),返回数组中的最大值。

通过掌握函数,你可以将复杂程序分解为小模块,使代码更易读、易维护。多练习不同类型的函数,逐步掌握参数传递、返回值和递归等核心概念。

0 条评论

目前还没有评论...