C语言 第七章 函数

第七章 函数

C源程序有函数组成:一个main函数和若干个其他函数组成,main函数调用其他函数

函数概述

参数

0多个,有的函数有1多个参数,有的函数没有参数

返回值

0~1个,有的函数有1个返回值,有的函数没有返回值

函数分两种

系统函数

又称为标准函数或库函数,如sqrt(), fabs(), rand()

需要包含对应的头文件才能调用: #include <xxx.h>

自定义函数

我们自己编写的函数,需要定义后才能调用

函数的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
函数的返回值类型 函数名(参数类型1 参数1, 参数类型2 参数2 ...)
{
语句...
}

例如:
// 无返回值的
void fun()
{
printf("This is a function");
}

// 有返回值的
int fun2()
{
return 1;
}

// 有参数,参数不可以简写成 int a,b
int max(int a, int b)
{
if(a>b)
return a;
else if(a<b)
return b;
else
return 0;
}

// 返回值类型包括(int, float, double, char...)

函数的调用

调用就使用,对有参数的函数,还要同时给出参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

void func(int p)
{
int d=2;
p=d++;
printf("%d\n", p);
}

int main()
{
int a=1;
fun(a);
printf("%d\n", a);
}

形式参数(简称形参)

在函数定义头部中的参数,在函数未被调用时,此参数无具体值。

1
2
3
4
5
// 这里的a,b就是形参
void max(int a, int b)
{
...
}

实际参数(简称实参)

调用函数时给出的具体参数,是有具体的值。

1
2
// 这里的1,2就属于实参
max(1,2);

函数的返回值

return调用返回

函数的好处

程序功能被细分为若干函数,每个函数负责一个小功能,main函数负责调度、指挥个函数的工作。

有return语句无return语句
有返回值的函数(名前非void)返回表达式的值,函数结束,返回系统默认值,函数结束函数中语句执行结 束后(执行到最后的}),返回系统默认 值,函数结束
无返回值的函数(名前有void)函数结束(无返回值) ;return 表达式 这是错误的函数中语句执行结 束后(执行到最后 的 } ),函数结束(无返回值)

函数的声明

C语言是按照顺序编译,所以要将其他函数放在main函数前面

1
2
3
4
5
6
7
8
9
void fun()
{
...
}

int main()
{
fun();
}

也可提前定义函数,避免出错,注意:在文件头部声明函数的时候,只可省略形参名,;不可省

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

void fun(int p);

int main()
{
fun();
}

void fun(int p)
{
...
}

递归

函数直接或间接的自己调用自己,称为递归。

递归程序,结构简练,可读性强。但执行时其时间和空间上的开销都比较大。

为防止自调用无休止的进行,在函数内必须设置调用终止的条件,否则程序将无法终止,被称为死递归。

递归的分析方法

与嵌套调用类似。

尽管每次调用的都是资深(同一函数),弹药把每次所调用的函数都看作是不同的函数,这些函数都具有相同的参数、返回值和语句。

经典题型

求阶乘

1
2
3
4
5
int recursion(int loop)
{
if(loop == 1 || loop == 0)return 1;
return loop*recursion(loop-1);
}

函数的作用域和存储类别

变量的作用域

局部变量

只在本函数内有效

若未赋初值,值为随机数

不同函数中可使用同名变量,形参和实参也可同名(形参也是函数内的变量)

在复合语句中定义变量(只在复合语句“块”内有效)

全局变量

全局变量在函数外定义的变量、

作用域:从变量定义处开始,到本程序文件末尾均有效(其中所有函数都能用)。

初始值自动为0。

全局变量可在多个函数中同时起作用,应尽量少用或不用全局变量。

不同存储类别的变量的特点

变量定义前加autostaticregister
存储位置内存动态存储区内存静态存储区CPU寄存器(没在内存)
作用域所在函数内,或所在复合语句 { } 内有效同auto同auto
生存期离开函数或{ }就消失永久保留同auto
初值随机数,初值重新赋值值为0,初值只赋一次同auto

编译预处理

宏定义,只会替换文本,不会计算

1
2
3
4
5
6
#define N 13

int main()
{
printf("%d", N);
}

先预处理,再编译;预处理部分不编译

预处理阶段将宏定义字符串替换

1
2
3
4
5
6
7
#define M (y*y+3*y)

语句为
s=3*M + 4*M;

预处理后
s=3*(y*y+3*y) + 4*(y*y+3*y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#define N 3+5
main()
{
printf("%d", 2*N);
}

// 预处理后
#include <stdio.h>

main()
{
printf("%d", 2*3+5 );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 此例为错误示例
#include <stdio.h>
#define N 3+5;
main()
{
printf("%d", 2*N);
}

// 预处理后,这种情况是错的,不能这么写
#include <stdio.h>

main()
{
printf("%d", 2*3+5; );
}
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#define PRINT printf("*");
main()
{ PRINT
}

// 预处理后
#include <stdio.h>

main()
{ printf("*");
}

头文件

预处理后会将头文件替换掉

1
2
#include <头文件名.h>
#include "头文件名.h"

c源程序 -> 预处理 -> 编译 -> 运行