C语言函数使用教程,函数定义、调用、参数传递与递归函数详解
C语言函数详如何自定函数实现代码复用与模块化编程?本文将带你进行详细的学习。
C语言函数的使用入门,深入了解函数的定义、调用、参数传递机制,包含返回值、作用域、递归函数等高级特性,助你实现代码模块化。
随着程序变得越来越复杂,将所有代码都写在main函数中会变得难以维护和理解。C语言通过函数将代码划分为独立的模块,让每个函数完成特定功能。这种模块化编程方法大大提高了代码的可读性、可维护性和复用性。
1. 什么是函数?
函数是完成特定任务的独立代码块,可以接收输入参数,返回处理结果。
函数的优势:
- 代码复用:一次定义,多次调用
- 模块化:将复杂问题分解为小问题
- 易于维护:修改只需在函数内部进行
- 提高可读性:通过函数名理解功能
2. 函数的定义和调用
函数定义语法:
返回类型 函数名(参数列表) {
    // 函数体
    return 返回值; // 如果返回类型不是void
}基本示例:
#include <stdio.h>
// 函数声明(函数原型)
void printHello();
int add(int a, int b);
// 主函数
int main() {
    printHello();  // 函数调用
    
    int result = add(5, 3);  // 函数调用并接收返回值
    printf("5 + 3 = %d\n", result);
    
    return 0;
}
// 函数定义:打印问候语
void printHello() {
    printf("Hello, World!\n");
}
// 函数定义:两数相加
int add(int a, int b) {
    return a + b;
}3. 函数参数:传值调用
C语言默认使用传值调用,函数接收的是参数的副本,不会影响原始变量。
#include <stdio.h>
// 交换两个数的值(错误版本)
void swapWrong(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    printf("函数内: a=%d, b=%d\n", a, b);
}
// 计算阶乘
int factorial(int n) {
    int result = 1;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }
    return result;
}
int main() {
    int x = 5, y = 10;
    
    printf("交换前: x=%d, y=%d\n", x, y);
    swapWrong(x, y);  // 传值调用
    printf("交换后: x=%d, y=%d\n", x, y);  // x,y的值未改变
    
    // 计算阶乘
    int num = 5;
    printf("%d! = %d\n", num, factorial(num));
    
    return 0;
}4. 函数返回值
函数可以通过return语句返回结果,返回类型必须与函数声明一致。
#include <stdio.h>
#include <stdbool.h>
// 返回最大值
int max(int a, int b) {
    return (a > b) ? a : b;
}
// 判断是否为偶数
bool isEven(int num) {
    return num % 2 == 0;
}
// 多个返回语句
char getGrade(int score) {
    if (score >= 90) return 'A';
    if (score >= 80) return 'B';
    if (score >= 70) return 'C';
    if (score >= 60) return 'D';
    return 'F';
}
int main() {
    printf("最大值: %d\n", max(10, 20));
    printf("15是偶数吗? %s\n", isEven(15) ? "是" : "否");
    printf("成绩等级: %c\n", getGrade(85));
    
    return 0;
}5. 函数原型声明
函数原型告诉编译器函数的接口信息,通常放在文件开头。
#include <stdio.h>
// 函数原型声明
double calculateCircleArea(double radius);
double calculateCircleCircumference(double radius);
void displayCircleInfo(double radius);
int main() {
    double r = 5.0;
    displayCircleInfo(r);
    return 0;
}
// 函数定义
double calculateCircleArea(double radius) {
    return 3.14159 * radius * radius;
}
double calculateCircleCircumference(double radius) {
    return 2 * 3.14159 * radius;
}
void displayCircleInfo(double radius) {
    printf("半径: %.2f\n", radius);
    printf("面积: %.2f\n", calculateCircleArea(radius));
    printf("周长: %.2f\n", calculateCircleCircumference(radius));
}6. 变量的作用域
变量的作用域决定了它在程序中的可见范围。
#include <stdio.h>
int globalVar = 100;  // 全局变量
void testFunction() {
    int localVar = 50;  // 局部变量
    static int staticVar = 0;  // 静态局部变量
    
    localVar++;
    staticVar++;
    
    printf("局部变量: %d, 静态变量: %d\n", localVar, staticVar);
}
int main() {
    printf("全局变量: %d\n", globalVar);
    
    testFunction();  // 局部变量: 51, 静态变量: 1
    testFunction();  // 局部变量: 51, 静态变量: 2
    testFunction();  // 局部变量: 51, 静态变量: 3
    
    // printf("%d", localVar);  // 错误!局部变量不可见
    
    return 0;
}7. 数组作为函数参数
数组作为函数参数时,传递的是数组首元素的地址。
#include <stdio.h>
// 打印数组
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
// 修改数组元素
void doubleArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;  // 会修改原始数组
    }
}
// 查找数组最大值
int findMax(int arr[], int size) {
    int max = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    return max;
}
int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int n = sizeof(numbers) / sizeof(numbers[0]);
    
    printf("原始数组: ");
    printArray(numbers, n);
    
    printf("最大值: %d\n", findMax(numbers, n));
    
    doubleArray(numbers, n);
    printf("加倍后的数组: ");
    printArray(numbers, n);
    
    return 0;
}8. 递归函数
递归函数是直接或间接调用自身的函数。
#include <stdio.h>
// 递归计算阶乘
int factorial(int n) {
    if (n <= 1) return 1;        // 基线条件
    return n * factorial(n - 1);  // 递归调用
}
// 递归计算斐波那契数列
int fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}
// 递归显示数字位数
void displayDigits(int n) {
    if (n < 10) {
        printf("%d ", n);
        return;
    }
    displayDigits(n / 10);
    printf("%d ", n % 10);
}
int main() {
    printf("5! = %d\n", factorial(5));
    
    printf("斐波那契数列前10项: ");
    for (int i = 0; i < 10; i++) {
        printf("%d ", fibonacci(i));
    }
    printf("\n");
    
    printf("12345的各位数字: ");
    displayDigits(12345);
    printf("\n");
    
    return 0;
}9. 实战案例:学生成绩管理系统
#include <stdio.h>
#define MAX_STUDENTS 100
// 函数原型
void inputScores(int scores[], int n);
void displayScores(int scores[], int n);
float calculateAverage(int scores[], int n);
int findMaxScore(int scores[], int n);
int findMinScore(int scores[], int n);
void sortScores(int scores[], int n);
int main() {
    int scores[MAX_STUDENTS];
    int numStudents;
    
    printf("请输入学生人数: ");
    scanf("%d", &numStudents);
    
    if (numStudents > MAX_STUDENTS) {
        printf("人数超过限制!\n");
        return 1;
    }
    
    inputScores(scores, numStudents);
    displayScores(scores, numStudents);
    
    printf("平均分: %.2f\n", calculateAverage(scores, numStudents));
    printf("最高分: %d\n", findMaxScore(scores, numStudents));
    printf("最低分: %d\n", findMinScore(scores, numStudents));
    
    sortScores(scores, numStudents);
    printf("排序后的成绩: ");
    displayScores(scores, numStudents);
    
    return 0;
}
void inputScores(int scores[], int n) {
    printf("请输入%d个学生的成绩:\n", n);
    for (int i = 0; i < n; i++) {
        printf("学生%d: ", i + 1);
        scanf("%d", &scores[i]);
    }
}
void displayScores(int scores[], int n) {
    printf("成绩列表: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", scores[i]);
    }
    printf("\n");
}
float calculateAverage(int scores[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += scores[i];
    }
    return (float)sum / n;
}
int findMaxScore(int scores[], int n) {
    int max = scores[0];
    for (int i = 1; i < n; i++) {
        if (scores[i] > max) {
            max = scores[i];
        }
    }
    return max;
}
int findMinScore(int scores[], int n) {
    int min = scores[0];
    for (int i = 1; i < n; i++) {
        if (scores[i] < min) {
            min = scores[i];
        }
    }
    return min;
}
void sortScores(int scores[], int n) {
    // 冒泡排序
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (scores[j] > scores[j + 1]) {
                int temp = scores[j];
                scores[j] = scores[j + 1];
                scores[j + 1] = temp;
            }
        }
    }
}10. 常见错误与最佳实践
常见错误1:忘记返回值
int add(int a, int b) {
    int result = a + b;
    // 忘记写 return result;
}常见错误2:函数原型不匹配
// 原型声明
void display(int num);
// 函数定义
int display(int num) {  // 错误!返回类型不匹配
    printf("%d", num);
}最佳实践:
- 为函数起有意义的名称
- 每个函数只完成一个明确的任务
- 使用函数原型声明
- 合理使用注释说明函数功能
- 避免过长的函数(通常不超过50行)
11. 总结
在本篇教程中,你学到了:
- 函数的定义、调用和原型声明
- 参数传递的传值机制
- 返回值的使用方法
- 变量的作用域规则
- 数组作为函数参数的用法
- 递归函数的原理和实现
- 模块化编程的实战应用
12. 动手练习
- 基础练习:编写函数判断一个数是否为素数。
- 进阶练习:编写递归函数计算两个数的最大公约数(GCD)。
- 挑战练习:使用函数模块化重构之前的成绩管理系统,添加成绩统计、等级评定等功能。