函数

函数概念

函数的存在能让代码复用性更大化,在很多重复的代码中,将重复的部分写成一个自己定义的函数,就只需要在主函数中调用定义函数中的变量去使用就好了

函数是一块代码,接受零个或者多个参数,做某件事情,并返回零个或者一个值

函数定义

1
2
3
4
void x (int i){ // 这一整行是函数头,void是返回类型 ,x 是函数名,(int i)是参数表

// 在大括号内的表达式是函数体
}

调用函数

  • 调用函数需要在调用它的地方中写上函数名(参数值)

  • () 起到了表达函数调用的重要作用,即使是定义的函数没有参数也需要写上()

  • 如果函数有参数,在调用的时候需要给出正确的数量和顺序

  • 这些传递给参数的值会被按照顺序依次用来初始化函数中的参数

  • 当存在多个参数表的时候,只需要按参数表的顺序去定义就好

  • 函数是知道每一次是哪里调用的,它会返回到正确的地方

  • 能够传递给函数的值是表达式的结果,其中表达式包括[字面量],[变量],[函数的返回值],[计算的结果]

返回值

  • 在函数中出现return时停止函数的执行,并送出一个值

  • 这个值会返回调用函数的地方

  • 虽然一个函数中可以出现多个return,但不管是在表达式中写return; 还是在末尾写return 表达式 都是可以的,但是建议只有单一出口

  • 函数的返回值可以复制给定义函数地方的变量,也可以再次传递给函数,甚至可以丢掉不再使用函数

空返回值

  • 当你需要定义的是没有返回值的函数时,需要把返回类型修改成void 函数名 (参数表)

  • 可以不需要在末尾带上return,如果带上return不能使用带值的return

  • 调用的时候不能做带有返回值的赋值

  • 但是如果函数有返回值,则必须使用带值的return

试试一个用函数实现的求和

  • 求出1~10 20~30 35~45的三个和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

void sum(int k, int o) {
int i;
int sum = 0;
for (i = k; i <= o; i++) {
sum += i;
}
printf("%d到%d的和是%d\n", k, o, sum);
}

int main() {
sum(1, 10); // void sum (int k = 1 ,int o = 10)
sum(20, 30); // void sum (int k = 20 ,int o = 30)
sum(35, 45); // void sum (int k = 35 ,int o = 45)
return 0;
}

函数顺序

C的编译器是自上而下顺序分析你写的代码

如果需要把定义函数写在main函数之下,需要在main函数之前申明一次

函数原型
  • 函数声明和函数定义的函数类型需要一致

  • 函数头以分号;结尾,就构成了函数的原型

  • 函数原型的目的的是告诉编译器你定义了一个或多个函数,需要调用时需要去寻找

  • 在函数原型中包含了函数名称,函数参数(数量以及类型),还有返回类型

  • 函数原型里不写参数名称也可以正常编译,但是一般为了方便理解代码最好是写上

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

void sum(int k, int o); // 这一整段叫函数原型 对函数的声明

int main() {
sum(1, 10); // void sum (int k = 1 ,int o = 10)
sum(20, 30); // void sum (int k = 20 ,int o = 30)
sum(35, 45); // void sum (int k = 35 ,int o = 45)
return 0;
}
void sum(int k, int o) { // 函数定义
int i;
int sum = 0;
for (i = k; i <= o; i++) {
sum += i;
}
printf("%d到%d的和是%d\n", k, o, sum);
}

类型转换

  • 调用函数的时给的值如果与参数的类型不一致很可能出现值的差错

  • 因为编译器会自动帮你把类型转换好

  • 如果你想传递的值是double类型,而函数中的参数类型是int,那么会自动转换成int类型

  • 在传递值的时候一定要严格按照函数中的类型去调用

函数传值

  • C语言在调用函数的时候,永远都只能传递值给函数

  • 每个函数都是一个独立空间,函数中的变量和参数都只存在于这个函数之中,和其他的函数没有任何关系

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

int swap(int a,int b); // 函数原型

int main() {
int a = 5;
int b = 6;
swap(a,b); // swap ( int a = 5, b = 6);
printf("%d%d",a,b); // 输出的是主函数中的a,b,与swap函数没有任何联系
return 0;
}

int swap(int a,int b){
int t = a;
a = b;
b = t;
}

局部(本地)变量

函数的每次运行都会产生一个独立的变量空间,在这个空间中的变量是函数这个运行所独有的,称之为本地变量

只要是在函数中定义的变量都叫做本地变量,参数表中的变量也一样是本地变量

生存期和作用域

函数的生存期和作用域起止于大括号内的代码块

  • 生存期: 从这个变量开始出现到它消亡的过程
  • 作用域: 从这个变量在代码中的什么范围内起作用
规则
  • 本地变量定义在块中
    • 可以定义在函数的块中
    • 可以定义在语句的块中
    • 可以定义在任意地方生成的大括号中
  • 程序运行进入定义了变量的块之前,其中的变量不存在,离开这个块的时候,其中的变量就消失了
  • 块外面定义的变量在不同块里面仍然有效
  • 块里面定义了和外面同名的变量就会覆盖外面的变量
  • 不能在同一个块内定义重名的变量
  • 本地变量不会被默认初始化
  • 而参数在进入函数的函数就已经被初始化了

其他

  1. 当函数没有参数的时候在原型的参数表中加上void可以明确表示没有任何参数void x (void)

    如果实际上有参数而在原型中没写上参数就可能因为传值出现一些奇奇怪怪的问题

  2. 在调用函数的时候里面的逗号只是标点符号,如果需要使用逗号运算符需要再加一层括号x((a,b)

  3. 函数不允许嵌套定义,但是可以在函数中写另一个函数的原型

  4. int main()也是函数,如果你不需要main有任何参数,也可以在()中加上void

评论