Skip to content

函数

函数是C语言程序的基本组成单位,用于实现特定功能的代码块。通过函数可以将程序分解为多个模块,提高代码的可读性和复用性。本章将详细介绍C语言函数的定义和使用。

函数基础

函数的定义

c
/*
 * 函数的定义
 */

#include <stdio.h>

/* 
 * 函数的基本结构:
 * 返回类型 函数名(参数列表)
 * {
 *     函数体
 *     return 返回值;
 * }
 */

/* 无参数无返回值的函数 */
void say_hello(void)
{
    printf("Hello, C!\n");
    /* void函数可以省略return */
}

/* 有参数无返回值的函数 */
void print_sum(int a, int b)
{
    printf("%d + %d = %d\n", a, b, a + b);
}

/* 有参数有返回值的函数 */
int add(int a, int b)
{
    return a + b;  /* 返回计算结果 */
}

/* 无参数有返回值的函数 */
int get_input(void)
{
    int num;
    printf("请输入一个数字: ");
    scanf("%d", &num);
    return num;
}

int main(void)
{
    /* 调用函数 */
    say_hello();           /* 调用无参无返回值函数 */
    
    print_sum(5, 3);       /* 调用有参无返回值函数 */
    
    int result = add(10, 20);  /* 调用有参有返回值函数 */
    printf("add(10, 20) = %d\n", result);
    
    int num = get_input();     /* 调用无参有返回值函数 */
    printf("你输入的数字是: %d\n", num);
    
    return 0;
}

函数声明

c
/*
 * 函数声明(函数原型)
 */

#include <stdio.h>

/* 函数声明:告诉编译器函数的存在 */
int max(int a, int b);      /* 函数原型 */
double average(int, int);   /* 参数名可以省略 */

int main(void)
{
    /* 在声明之后就可以调用函数 */
    int m = max(10, 20);
    printf("最大值: %d\n", m);
    
    double avg = average(10, 20);
    printf("平均值: %.2f\n", avg);
    
    return 0;
}

/* 函数定义:在main函数之后 */
int max(int a, int b)
{
    return (a > b) ? a : b;
}

double average(int a, int b)
{
    return (a + b) / 2.0;
}

参数传递

值传递

c
/*
 * 值传递(传值)
 */

#include <stdio.h>

/* 尝试交换两个数(错误示例) */
void swap_wrong(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
    printf("函数内: a = %d, b = %d\n", a, b);
}

/* 正确的交换(使用指针) */
void swap_correct(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main(void)
{
    int x = 5, y = 10;
    
    /* 值传递:函数内修改不影响原变量 */
    printf("调用前: x = %d, y = %d\n", x, y);
    swap_wrong(x, y);
    printf("调用后: x = %d, y = %d\n", x, y);  /* 值未改变 */
    
    /* 指针传递:可以修改原变量 */
    printf("\n使用指针:\n");
    printf("调用前: x = %d, y = %d\n", x, y);
    swap_correct(&x, &y);
    printf("调用后: x = %d, y = %d\n", x, y);  /* 值已交换 */
    
    return 0;
}

数组作为参数

c
/*
 * 数组作为函数参数
 */

#include <stdio.h>

/* 数组参数会退化为指针 */
void print_array(int arr[], int len)
{
    /* sizeof(arr) 是指针的大小,不是数组大小 */
    for (int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

/* 等价的写法 */
void print_array2(int *arr, int len)
{
    for (int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

/* 修改数组元素 */
void double_array(int arr[], int len)
{
    for (int i = 0; i < len; i++) {
        arr[i] *= 2;  /* 修改会影响原数组 */
    }
}

/* 计算数组元素和 */
int array_sum(int arr[], int len)
{
    int sum = 0;
    for (int i = 0; i < len; i++) {
        sum += arr[i];
    }
    return sum;
}

/* 二维数组作为参数 */
void print_2d_array(int rows, int cols, int arr[rows][cols])
{
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

int main(void)
{
    int arr[] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    print_array(arr, len);
    print_array2(arr, len);
    
    double_array(arr, len);
    printf("翻倍后: ");
    print_array(arr, len);
    
    int sum = array_sum(arr, len);
    printf("数组元素和: %d\n", sum);
    
    /* 二维数组 */
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    printf("\n二维数组:\n");
    print_2d_array(2, 3, matrix);
    
    return 0;
}

变量的作用域

c
/*
 * 变量的作用域和生命周期
 */

#include <stdio.h>

/* 全局变量:在整个程序中可见 */
int global_var = 100;

/* 静态全局变量:只在当前文件可见 */
static int file_var = 200;

void func1(void)
{
    /* 访问全局变量 */
    printf("func1: global_var = %d\n", global_var);
    
    /* 局部变量:只在函数内可见 */
    int local_var = 10;
    printf("func1: local_var = %d\n", local_var);
    
    /* 静态局部变量:生命周期是整个程序 */
    static int count = 0;
    count++;
    printf("func1: count = %d\n", count);
}

void func2(void)
{
    /* 可以访问全局变量 */
    printf("func2: global_var = %d\n", global_var);
    
    /* 不能访问func1的局部变量 */
    /* printf("%d", local_var); */  /* 错误 */
    
    /* 同名的局部变量会隐藏全局变量 */
    int global_var = 999;
    printf("func2: local global_var = %d\n", global_var);
    
    /* 使用::访问全局变量(C不支持,C++支持) */
    /* printf("%d", ::global_var); */
}

/* 块作用域 */
void block_scope(void)
{
    int x = 10;
    printf("外层 x = %d\n", x);
    
    {
        int x = 20;  /* 新的x,隐藏外层的x */
        printf("内层 x = %d\n", x);
    }
    
    printf("外层 x = %d\n", x);  /* 恢复外层的x */
}

int main(void)
{
    printf("=== 全局变量 ===\n");
    printf("main: global_var = %d\n", global_var);
    
    printf("\n=== 局部变量 ===\n");
    func1();
    func1();  /* count会保持上次的值 */
    
    printf("\n=== 同名变量 ===\n");
    func2();
    
    printf("\n=== 块作用域 ===\n");
    block_scope();
    
    return 0;
}

递归函数

c
/*
 * 递归函数
 */

#include <stdio.h>

/* 递归计算阶乘 */
long long factorial(int n)
{
    /* 基准情况(终止条件) */
    if (n <= 1) {
        return 1;
    }
    /* 递归调用 */
    return n * factorial(n - 1);
}

/* 递归计算斐波那契数列 */
long long fibonacci(int n)
{
    if (n <= 0) return 0;
    if (n == 1) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

/* 递归计算数字各位之和 */
int digit_sum(int n)
{
    if (n < 10) {
        return n;
    }
    return (n % 10) + digit_sum(n / 10);
}

/* 递归打印数字 */
void print_digits(int n)
{
    if (n >= 10) {
        print_digits(n / 10);
    }
    printf("%d ", n % 10);
}

/* 递归实现二分查找 */
int binary_search(int arr[], int left, int right, int target)
{
    if (left > right) {
        return -1;  /* 未找到 */
    }
    
    int mid = left + (right - left) / 2;
    
    if (arr[mid] == target) {
        return mid;
    } else if (arr[mid] > target) {
        return binary_search(arr, left, mid - 1, target);
    } else {
        return binary_search(arr, mid + 1, right, target);
    }
}

/* 汉诺塔问题 */
void hanoi(int n, char from, char to, char aux)
{
    if (n == 1) {
        printf("移动盘子1从%c%c\n", from, to);
        return;
    }
    
    hanoi(n - 1, from, aux, to);
    printf("移动盘子%d%c%c\n", n, from, to);
    hanoi(n - 1, aux, to, from);
}

int main(void)
{
    /* 阶乘 */
    printf("5! = %lld\n", factorial(5));
    printf("10! = %lld\n", factorial(10));
    
    /* 斐波那契 */
    printf("\n斐波那契数列前10项:\n");
    for (int i = 1; i <= 10; i++) {
        printf("%lld ", fibonacci(i));
    }
    printf("\n");
    
    /* 数字各位之和 */
    printf("\n12345各位之和: %d\n", digit_sum(12345));
    
    /* 打印数字各位 */
    printf("12345各位数字: ");
    print_digits(12345);
    printf("\n");
    
    /* 二分查找 */
    int arr[] = {1, 3, 5, 7, 9, 11, 13, 15};
    int len = sizeof(arr) / sizeof(arr[0]);
    int target = 7;
    int index = binary_search(arr, 0, len - 1, target);
    printf("\n%d在数组中的索引: %d\n", target, index);
    
    /* 汉诺塔 */
    printf("\n3个盘子的汉诺塔:\n");
    hanoi(3, 'A', 'C', 'B');
    
    return 0;
}

内联函数

c
/*
 * 内联函数(C99)
 */

#include <stdio.h>

/* 内联函数:建议编译器内联展开 */
inline int square(int x)
{
    return x * x;
}

/* 静态内联函数 */
static inline int cube(int x)
{
    return x * x * x;
}

int main(void)
{
    int a = 5;
    
    /* 内联函数调用 */
    printf("%d的平方: %d\n", a, square(a));
    printf("%d的立方: %d\n", a, cube(a));
    
    /* 内联函数适用于:
     * 1. 函数体较小
     * 2. 调用频繁
     * 3. 执行时间短
     */
    
    return 0;
}

可变参数函数

c
/*
 * 可变参数函数
 */

#include <stdio.h>
#include <stdarg.h>  /* 可变参数相关宏 */

/* 计算多个整数的和 */
int sum(int count, ...)
{
    va_list args;       /* 声明可变参数列表 */
    int total = 0;
    
    va_start(args, count);  /* 初始化args,count是最后一个固定参数 */
    
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);  /* 获取下一个int类型的参数 */
    }
    
    va_end(args);       /* 清理可变参数列表 */
    
    return total;
}

/* 计算多个整数的平均值 */
double average(int count, ...)
{
    va_list args;
    double total = 0;
    
    va_start(args, count);
    
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);
    }
    
    va_end(args);
    
    return total / count;
}

/* 简化版printf */
void my_printf(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    
    while (*format) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'd':
                    printf("%d", va_arg(args, int));
                    break;
                case 'f':
                    printf("%f", va_arg(args, double));
                    break;
                case 'c':
                    printf("%c", va_arg(args, int));
                    break;
                case 's':
                    printf("%s", va_arg(args, char*));
                    break;
                case '%':
                    putchar('%');
                    break;
                default:
                    putchar(*format);
            }
        } else {
            putchar(*format);
        }
        format++;
    }
    
    va_end(args);
}

int main(void)
{
    /* 计算和 */
    printf("sum(3, 1, 2, 3) = %d\n", sum(3, 1, 2, 3));
    printf("sum(5, 1, 2, 3, 4, 5) = %d\n", sum(5, 1, 2, 3, 4, 5));
    
    /* 计算平均值 */
    printf("average(4, 1, 2, 3, 4) = %.2f\n", average(4, 1, 2, 3, 4));
    
    /* 自定义printf */
    printf("\n自定义printf:\n");
    my_printf("整数: %d, 浮点: %f, 字符: %c, 字符串: %s\n", 
              42, 3.14, 'A', "Hello");
    
    return 0;
}

函数指针

c
/*
 * 函数指针
 */

#include <stdio.h>
#include <stdlib.h>

/* 普通函数 */
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; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }

/* 使用函数指针作为参数 */
int calculate(int a, int b, int (*operation)(int, int))
{
    return operation(a, b);
}

/* 回调函数示例 */
void process_array(int arr[], int len, void (*process)(int*))
{
    for (int i = 0; i < len; i++) {
        process(&arr[i]);
    }
}

void double_value(int *n) { *n *= 2; }
void square_value(int *n) { *n *= *n; }

/* 函数指针数组 */
int main(void)
{
    /* 声明函数指针 */
    int (*op)(int, int);
    
    /* 指向add函数 */
    op = add;
    printf("add(10, 5) = %d\n", op(10, 5));
    
    /* 指向subtract函数 */
    op = subtract;
    printf("subtract(10, 5) = %d\n", op(10, 5));
    
    /* 使用函数指针作为参数 */
    printf("\ncalculate(10, 5, add) = %d\n", calculate(10, 5, add));
    printf("calculate(10, 5, multiply) = %d\n", calculate(10, 5, multiply));
    
    /* 函数指针数组 */
    int (*operations[])(int, int) = {add, subtract, multiply, divide};
    char *op_names[] = {"加", "减", "乘", "除"};
    
    printf("\n计算器:\n");
    for (int i = 0; i < 4; i++) {
        printf("10 %s 5 = %d\n", op_names[i], operations[i](10, 5));
    }
    
    /* 回调函数 */
    int arr[] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    printf("\n原数组: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    
    process_array(arr, len, double_value);
    printf("\n翻倍后: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    
    process_array(arr, len, square_value);
    printf("\n平方后: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    printf("\n");
    
    return 0;
}

小结

本章学习了:

  • 函数定义:返回类型、函数名、参数列表、函数体
  • 函数声明:函数原型,先声明后使用
  • 参数传递:值传递、指针传递、数组传递
  • 变量作用域:局部变量、全局变量、静态变量
  • 递归函数:函数调用自身
  • 内联函数:建议编译器内联展开
  • 可变参数:va_list、va_start、va_arg、va_end
  • 函数指针:指向函数的指针

下一章,我们将学习数组,了解C语言数组的定义和使用。