156 lines
4.6 KiB
Markdown
Raw Normal View History

# 2.2 函数
## 2.2.1 函数基础
所谓函数,是指按照某种规律,将输入转变成输出的系统。
我们可以用c语言描述这样的系统。
```cpp
int fun0(int a, int b)
{
2018-03-21 09:26:31 +08:00
  return (a+b)*(a-b);
}
```
2018-03-21 09:26:31 +08:00
以上是一个函数的定义,可以看出,定义函数需采用以下语法结构:
2018-03-21 09:26:31 +08:00
2018-03-21 23:37:47 +08:00
返回值类型 函数名(参数类型 参数1, ... ,参数类型 参数n)
{
函数体
2018-03-21 09:26:31 +08:00
}
函数的命名规则与变量的命名规则一致只能包括下划线英文字符和0~9数字并且数字不能作为首字母出现。
函数的参数是一组仅在函数内部可见的变量,这些变量的值,由调用者传入:
```cpp
2018-03-21 23:37:47 +08:00
int a = 5;
fun0(a, 3); // 计算(5+3)*(5-3).
```
在定义函数的时候写的参数名称称作形式参数简称形参。而这里在调用时传入的a和3称作实际参数简称实参。
函数的返回值通过 **return** 语句返回给调用者:
```cpp
int c = fun0(5, 3); // c=16.
```
函数可以没有输入,此时函数的参数列表应该为 **void**,或者不写。
```cpp
int fun1(void)
{
2018-03-21 23:37:47 +08:00
  return 9; // fun1不依赖任何参数固定返回整数9.
}
```
函数也可能没有返回值,此时返回类型为 **void**
```cpp
void fun2(int a)
{
2018-03-21 23:37:47 +08:00
  printf("A = %d.\n", a); // 函数不返回任何内容仅打印参数a的值.
}
int b;
2018-03-21 23:37:47 +08:00
b = fun2(0x10); // 这种写法是错的因为fun2没有返回值所以无法为变量b赋值.
```
对于大部分 c/c++ 程序而言,有一个特殊的函数,它是整个程序的总入口——**main**函数。**main**函数的第一条语句便是整个程序的第一条指令。
```cpp
#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** 函数的形式如下:
```cpp
int main(int argc, char* argv[])
{
  ...
}
```
## 2.2.2 函数调用
函数之间可以相互调用,例如在 fun3 中调用 fun4 的代码如下:
```cpp
/**
* @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;
}
```
有一种非常独特的函数调用方法,被称作第归调用:
```cpp
/**
* @file example1.c
*/
void fun5(void)
{
fun5();
}
int main(void)
{
fun5();
return 0;
}
```
在上面程序中,**main** 函数中的 **return** 语句永远不会被执行。因为 fun5 这个函数不断的调用自己,致使程序一直被执行下去。
2018-06-05 20:57:09 +08:00
实际上每次调用函数都会压栈fun5 无穷无穷尽的调用自己,只会导致堆栈溢出,或者被看门狗检测到死循环。通常,我们不会这样编写程序,而是在 fun5 中增加条件判断,在某些情况下不再调用自己,从而使程序可以返回。第归调用在某些情况下是非常有用的。
## 练习
1、编写第归调用程序解决下列问题
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
2、韩信为了知道多少兵同时又不让敌人知道士兵数目便让士兵排队报数
按1~5报数最后一个士兵报数为1
按1~6报数最后一个士兵报数为5
按1~7报数最后一个士兵报数为4
按1~11报数最后一个士兵报数为10
求韩信有多少兵?