函数
本文最后更新于136 天前,其中的信息可能已经过时,如有错误请发送邮件至 2641805259@qq.com

一、概述

函数是 C 语言程序的基本结构单元,用于封装可复用的计算逻辑。使用函数能够提升代码模块化程度、可维护性与可扩展性。


二、函数的组成

C 语言中的函数通常包含三部分:

  • 函数声明(Prototype):告知编译器函数的名称参数返回类型
  • 函数定义(Definition):函数的实际实现。
  • 函数调用(Call):执行函数逻辑并获取返回值。

示例:f(x) R y = f(x) = x^2 x = 2

int add(int a, int b);              // 声明


int add(int a, int b) { return a+b; }  // 定义


add(3, 5);                           // 调用

三、函数的定义

1. 基本格式

返回类型 函数名(参数列表)
{
    // 函数体
}

示例:

int max(int x, int y)
{
    if (x > y)
        return x; // 退出函数
    return y;
}

四、函数的声明

函数声明的作用是在定义之前向编译器提供函数接口信息。例如:

返回值 函数名(传入的参数)

int max(int x, int y);


声明可放在文件开头或头文件中,便于分离编译。


五、函数调用

调用方式:

result = max(10, 20);

实参与形参之间采用值传递机制,形参 n接收的是实参 a的副本。

示例:

#include <stdio.h>

int square(int n)
{
    n = n + 1;
    return n * n;
}

int main()
{
    int a = 5;
    int r = square(a);
    printf("%d\n%d", r, a);
    return 0;
}
  • 函数调用需要在函数声明之后

六、返回值与返回语句

  • 使用 return 返回表达式的值。
  • 返回类型必须与函数声明一致。
  • 函数不能返回数组
  • 无返回值时使用 void

示例:

void hello()
{
    printf("Hello\n");
}

bool big(int a, int b){
    return a < b;
}

七、参数传递与作用

C 语言采用值传递:函数内部修改形参不会 影响外部变量。

示例:

#include <stdio.h>

void setZero(int a)
{
    a = 0;
}

int main()
{
    int a = 10;
    setZero(a);
    printf("a = %d\n", a);  // 输出仍为 10
    return 0;
}

当需要修改外部变量时使用指针(扩展内容)。

传递数字型参数

在 C 语言中,数组作为函数参数时会退化为指向首元素的指针。因此函数接收的是指针形式,无法从参数本身获知数组长度,需显式传递长度。

1. 典型定义方式

void printArray(int arr[], int n)
{
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("
");
}

等价写法:

void printArray(int *arr, int n)

2. 调用方式

int a[5] = {1, 2, 3, 4, 5};
printArray(a, 5);

3. 修改数组内容

函数内部可修改数组元素,外部可见。

void setZero(int arr[], int n)
{
    for (int i = 0; i < n; i++)
        arr[i] = 0;
}

int main(){
    int arr[3] = {1, 2, 3};
    setZero(arr);	// 传入只需要传名称
}

4. 多维数组的传递

二维数组需指定列数:

void show(int *arr[4], int r)
{
    for (int i = 0; i < r; i++)
        for (int j = 0; j < 4; j++)
            printf("%d ", arr[i][j]);
}

八、静态变量与生命周期

函数中的变量默认为自动变量,每次调用创建并销毁。使用 static让变量在多次调用间保持状态

示例:

#include <stdio.h>

void counter()
{
    static int c = 0;
    c++;
    printf("c = %d\n", c);
}

int main()
{
    counter();
    counter();
    counter();
    return 0;
}

输出依次为 1,2,3。


九、函数与多文件模块化

目录结构示例

project/
├── main.c
├── math.c
└── math.h

math.h 用于函数声明以及全局变量声明

#ifndef MATH_H
#define MATH_H

int add(int a, int b);
int sub(int a, int b);

#endif

math.c 用于函数的定义

#include "math.h"

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

main.c

#include <stdio.h>
#include "math.h"

int main()
{
    printf("%d\n", add(3, 7));
    printf("%d\n", sub(10, 5));
    return 0;
}

编译方式(MinGW-w64):

gcc main.c math.c -o app.exe

十、设计函数的原则

  • 单一职责:每个函数只完成一个逻辑任务。
  • 命名清晰:函数名应准确描述其行为。
  • 控制长度:尽量避免过长函数(>80 行)。

十一、综合示例

以下示例展示一个输入、处理与输出分离的函数结构:

#include <stdio.h>

int readNumber()
{
    int x;
    scanf("%d", &x);
    return x;
}

int compute(int a, int b)
{
    return a * b + 10;
}

void showResult(int r)
{
    printf("Result = %d\n", r);
}

int main()
{
    int x = readNumber();
    int y = readNumber();
    int r = compute(x, y);
    showResult(r);
    return 0;
}

十二、函数递归入门

递归是一种函数直接或间接调用自身的编程方式。其关键是将大问题分解为更小的同类子问题,并设置终止条件。

1. 递归的结构

递归函数通常包含两部分:

  • 基本情况(终止条件):不再递归时的返回值。
  • 递归情况:将问题拆分为规模更小的同类问题。

典型示例:

int n = 5;
result = factorial(5);
int factorial(int n)
{
    if (n == 0)
        return 1;            // 基本情况
    return n * factorial(n - 1);  // 递归调用
}
stackoverflow 栈溢出

result = factorial(5);

factorial(5) = 5 * factorial(4); = 120 = 5!

f(4) = 4 * f(3) =24

f(3) = 3 * f(2) = 6

f(2) = 2 * f(1) = 2

f(1) = 1 * f(0) = 1

f(0) = 1;

 

n! = n * (n – 1)!

2. 使用递归的必要条件

  • 子问题必须继续向终止条件收敛。
  • 每次调用都应缩小问题规模。
  • 必须避免无限递归。

3. 经典示例

(1) Fibonacci 数列

int fib(int n)
{
    if (n <= 1)
        return n;
    return fib(n - 1) + fib(n - 2);
}

1 1 2 3 5 8 13

fib(7)

f(7) = f(6) + f(5)

f(6) = f(5) + f(4)

尾递归

递归在函数return 的时候调用

(2) 递归遍历数组

void printArray(int arr[], int n)
{
    if (n == 0)
        return;
    printArray(arr, n - 1);
    printf("%d ", arr[n - 1]);
}

4. 递归与栈

每次递归调用都会占用栈空间保存现场,包括参数与返回地址。深度过大可能导致栈溢出。适当情况下需使用迭代替代递归。

十三、总结

本讲义覆盖函数的完整使用方法,包括声明、定义、调用、值传递机制、静态变量、多文件组织结构等内容,适合作为系统学习 C 语言函数的参考材料。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇