Chapter2_C与C++——2.2 函数

2.2 函数

2.2.1 函数基础

所谓函数,是指按照某种规律,将输入转变成输出的系统。
我们可以用c语言描述这样的系统。

int fun0(int a, int b)
{
    return (a+b)*(a-b);
}

以上是一个函数的定义,可以看出,定义函数需采用以下语法结构:

返回值类型 函数名(参数类型 参数1, ... ,参数类型 参数n)
{
    函数体
}

函数的命名规则与变量的命名规则一致,只能包括下划线,英文字符和0~9数字,并且数字不能作为首字母出现。
函数的参数是一组仅在函数内部可见的变量,这些变量的值,由调用者传入:

int a = 5;
fun0(a, 3);  // 计算(5+3)*(5-3).

在定义函数的时候写的参数名称称作形式参数,简称形参。而这里在调用时传入的a和3称作实际参数,简称实参。
函数的返回值通过 return 语句返回给调用者:

int c = fun0(5, 3);  // c=16.

函数可以没有输入,此时函数的参数列表应该为 void,或者不写。

int fun1(void)
{
    return 9;   // fun1不依赖任何参数,固定返回整数9.
}

函数也可能没有返回值,此时返回类型为 void

void fun2(int a)
{
    printf("A = %d.\n", a); // 函数不返回任何内容,仅打印参数a的值.
}

int b;
b = fun2(0x10);     // 这种写法是错的,因为fun2没有返回值,所以无法为变量b赋值.

对于大部分 c/c++ 程序而言,有一个特殊的函数,它是整个程序的总入口——main函数。main函数的第一条语句便是整个程序的第一条指令。

#include <stdio.h>    // 包含printf等标准输入输出函数

int fun0(int a, int b)
{
    return (a+b)*(a-b);
}

int main(void)
{
    int a=5, b=3;

    printf("我是第一条被执行的语句!\n");
    printf("a^2-b^2=%d", fun0(a, b));
    printf("我是第三条被执行的语句!\n");
    return 0;
}

以上,是我们迄今为止编写的最完整的 c 语言程序。它包含了该程序的总入口函数 mian,定义并初始化了两个局部变量 a 和 b,通过 printf 语句进行了一些输出,return 0 代表程序正确执行。另外,我们定义了了一个函数 fun0,并且为了让程序能被编译通过,我们通过 include 包含了一些c标准库对外声明的函数等,用于声明 printf 函数。
以上你所见的,是所有 main 函数形式中的一种。main 函数不但可以返回零,还可以返回其他值给调用者。也可以接收来自调用者传入的一些参数,这时候 main 函数的形式如下:

int main(int argc, char* argv[])
{
    ...
}

2.2.2 函数调用

函数之间可以相互调用,例如在 fun3 中调用 fun4 的代码如下:

/**
 * @file    example0.c
 */
#include <stdio.h>

static void fun4(void);   // 由于 fun4 是在被使用后定义的,因此需要在使用前声明.

void fun3(void)
{
    printf("This fun3.\n");
    fun4();    // 调用 fun4.
}

/**
 * @brief   static 关键字限定了 fun4 只能在本文件中使用,不能在其他文件中使用.
 */
static void fun4(void)
{
    printf("This fun4.\n");
}

int main(void)
{
    fun3();    // fun3 是在 main 函数前定义的,因此不需要再次声明.
    return 0;
}

有一种非常独特的函数调用方法,被称作第归调用:

/**
 * @file    example1.c
 */

void fun5(void)
{
    fun5();
}

int main(void)
{
    fun5();
    return 0;
}

在上面程序中,main 函数中的 return 语句永远不会被执行。因为 fun5 这个函数不断的调用自己,致使程序一直被执行下去。
实际上,每次调用函数都会压栈,fun5 无穷无穷尽的调用自己,只会导致堆栈溢出,或者被看门狗检测到死循环。通常,我们不会这样编写程序,而是在 fun5 中增加条件判断,在某些情况下不再调用自己,从而使程序可以返回。第归调用在某些情况下是非常有用的。

练习

1、编写第归调用程序解决下列问题:
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

2、韩信为了知道多少兵,同时又不让敌人知道士兵数目,便让士兵排队报数:

按1~5报数,最后一个士兵报数为1;  
按1~6报数,最后一个士兵报数为5;  
按1~7报数,最后一个士兵报数为4;  
按1~11报数,最后一个士兵报数为10;  

求韩信有多少兵?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章