“先生,不是在这种环境下。因此我也被编写了三十多个辅助功能——”

——C3PO,在被粗鲁打断之前,报告一个并不出色的额外功能数量,《星球大战》剧本

和你熟悉的其他语言非常类似,C 语言也有函数(functions)的概念。

函数可以接受各种参数(arguments),并返回一个值。不过有一点很重要:参数和返回值的类型是预先声明的——因为 C 就是这样喜欢的!

我们来看一个函数示例。这个函数接受一个 int 作为参数,并返回一个 int

#include <stdio.h>

int plus_one(int n)  // 这是函数的“定义”
{
    return n + 1;
}

函数名前的 int 表示返回值类型。

int n 表示这个函数接收一个 int 类型的参数,存储在名为 n 的参数变量中。参数是局部变量的一种特殊类型,函数调用时会将传入的值复制给它。

我要强调的一点是,参数是被复制到形参中的。只要明白形参是实参的一个副本,而不是实参本身,许多 C 语言的概念就更容易理解。稍后会详细讲解这个内容。

继续看程序中的 main() 函数,我们可以看到对函数的调用,并且将返回值赋给了局部变量 j

int main(void)
{
    int i = 10, j;

    j = plus_one(i);  // 这是函数调用

    printf("i + 1 is %d\\n", j);
}

顺便说一下,要注意我是在使用函数之前先定义了它。如果不这样做,编译器在编译 main() 时还不知道 plus_one 存在,就会报“未知函数调用”错误。

事实上,上面的代码更合适的写法是使用函数原型(function prototypes),但我们稍后会讲这个内容。

另外要注意,main() 也是一个函数!

它返回一个 int 类型的值。

那么,void 是什么?它是一个关键字,用来表示函数不接受任何参数。

你也可以使用 void 作为返回类型,表示函数不返回任何值:

#include <stdio.h>

// 这个函数不接受参数,也不返回值:
void hello(void)
{
    printf("Hello, world!\\n");
}

int main(void)
{
    hello();  // 输出 "Hello, world!"
}

4.1 Passing by Value

我之前提到过,当你把一个参数传递给函数时,会对该参数进行复制,并存储到对应的形参中。