第1章:函数基础——函数的定义与声明、参数、返回值与return语句

说实话,函数这东西,是C语言里最基础也最核心的概念之一。我刚开始学的时候,总觉得函数就是“把代码包起来重复用”,后来做项目多了才发现——函数的设计好坏,直接决定了代码能不能维护、能不能扩展。

今天咱们就把函数的基础彻底讲透。你想想看,一个函数无非就三件事:定义它、调用它、让它返回结果。但这里面的门道,可不少。

1.1 函数的定义:给代码一个名字

函数的定义,说白了就是告诉编译器:“嘿,我这儿有一段逻辑,以后你看到这个名字,就执行这段代码。”

一个完整的函数定义长这样:

返回类型 函数名(参数列表)
{
    // 函数体
    // 一系列语句
    return 返回值;
}

举个例子,我写一个计算两个整数平均值的函数:

int average(int a, int b)
{
    int sum = a + b;
    return sum / 2;
}

这里 int 是返回类型,average 是函数名,int a, int b 是参数列表。函数体里做了加法、除法,最后用 return 把结果送回去。

我的习惯:函数名一定要见名知意。我见过太多人写 func1()doSomething(),三个月后自己都看不懂。命名花不了几秒钟,但能省下几小时的调试时间。

1.2 函数的声明:先打个招呼

函数的声明,也叫函数原型。它的作用就是告诉编译器:“这个函数存在,参数和返回值长这样,你先别报错,后面我会定义它。”

声明和定义的区别,我打个比方:
声明就像你告诉朋友“我明天要请你吃饭”——先打个招呼。
定义就像你真正把菜端上桌——具体实现。

声明的格式:

返回类型 函数名(参数类型列表);

注意最后有个分号。比如:

int average(int a, int b);  // 声明
// 或者省略参数名也行:
int average(int, int);      // 也合法

为什么要声明?因为C语言是顺序编译的。如果你在 main() 里调用了一个还没定义的函数,编译器会报错。声明放在文件开头,就能解决这个问题。

我曾经踩过的坑:有一次我写了一个多文件项目,忘了在头文件里声明函数,结果在另一个.c文件里直接调用。链接的时候报了一堆“未定义引用”的错误。排查了半天才发现——声明没写。从那以后,我每个函数都在对应的头文件里先声明一遍,养成习惯。

1.3 形参与实参:名字不同,本质不同

这两个概念,很多初学者容易搞混。我直接说人话:

  • 形参(形式参数):写在函数定义里的参数,比如 int average(int a, int b) 里的 ab。它们只是“占位符”,没有实际的值。
  • 实参(实际参数):调用函数时传进去的具体值,比如 average(10, 20) 里的 1020。它们是实实在在的数据。

看个例子就明白了:

#include <stdio.h>

int average(int a, int b)  // a和b是形参
{
    return (a + b) / 2;
}

int main()
{
    int x = 10, y = 20;
    int result = average(x, y);  // x和y是实参
    printf("平均值为:%d\n", result);
    return 0;
}

这里 xy 的值被复制给了 ab。函数内部修改 ab,不会影响外面的 xy。这就是值传递

记住一句话:形参是实参的“复印件”。复印件上涂改,原件不受影响。

1.4 函数的返回值:函数能给你什么

函数的返回值,就是函数执行完后,交回给调用者的结果。返回值类型在函数定义时指定:

  • int:返回整数
  • floatdouble:返回浮点数
  • char:返回字符
  • void:什么都不返回

举个例子:

int add(int x, int y)
{
    return x + y;  // 返回一个int
}

void printMessage()
{
    printf("Hello!\n");  // 没有return,也不需要返回值
}

注意:如果函数声明了返回类型(非void),那么函数体内必须return 语句,并且返回值的类型要匹配。否则编译器会警告,甚至报错。

我个人的建议:即使函数返回类型是 void,我有时也会在末尾加一个 return;。虽然不强制,但能让代码逻辑更清晰——明确告诉读者“我执行完了,这里结束”。

1.5 return语句:把结果送回去

return 语句有两个作用:

  1. 结束函数的执行——遇到 return,函数立刻返回,后面的代码不再执行。
  2. 返回一个值——把结果传给调用者。

看个例子:

int max(int a, int b)
{
    if (a > b)
        return a;  // 如果a大,直接返回a,函数结束
    else
        return b;  // 否则返回b
    // 这里永远不会执行到
}

注意:一个函数可以有多个 return 语句,但每个 return 都会导致函数立即结束。这在逻辑判断时非常有用。

我曾经犯过的错:写了一个函数,返回类型是 int,但某个分支忘了写 return。编译器只给了个警告,我没在意。结果程序运行时,那个分支返回了一个随机值(栈上的垃圾数据),导致整个系统行为异常。从那以后,我每个分支都检查 return 是否齐全。

1.6 知识体系总览

下面这张图,把函数基础的核心知识点串起来了。你可以把它当作本章的“地图”:

函数基础 定义 vs 声明 定义:写函数体,实现逻辑 声明:告诉编译器函数存在 参数 形参:占位符,无实际值 实参:具体值,调用时传入 返回值 有返回值:return 表达式 无返回值:void + return; return语句 结束函数 + 返回值 核心:定义 → 声明 → 调用 → 返回

1.7 小结

函数基础,说白了就是三件事:定义、参数、返回值。定义告诉编译器“怎么做”,参数告诉函数“用什么数据”,返回值告诉调用者“得到了什么结果”。

嗯,这里要注意:函数声明和定义不要搞混。声明只是打个招呼,定义才是真正干活。形参和实参虽然名字像,但一个是占位符,一个是真实数据。return语句既是“结束信号”,也是“结果传递”。

我个人觉得,函数是C语言里最值得花时间搞懂的概念之一。你把它吃透了,后面学指针、结构体、文件操作都会轻松很多。


公众号:蓝海资料掘金营,微信deep3321