函数
完成某种特定功能的指令序列集合的集合
函数作用
- 实现代码的复用(高内聚、低耦合)
- 实现模块化设计
- 函数可以灵活组合调用
函数的设计
- 需求分析:函数是干什么的,完成什么功能,需要什么资源
- 函数的功能实现:算法
- 需不需要返回一个结果
函数的定义
// 函数头
返回值类型 函数名(形参列表)
// 函数体
{
函数的具体实现步骤(具体功能实现的代码);
}
// 一个标准的函数
返回值类型 函数名(形参列表)
{
函数的具体实现步骤(具体功能实现的代码);
}
- 返回值类型:一般是单值类型,即基本类型、指针类型、构造类型。也可以返回空 void,如果不指定返回值类型的话,默认就是int类型
- 函数名:c语言标识符,要符合标识符命名规范
- 形参列表:需要外部调用者提供的资源,格式:(数据类型1 数据名1, 数据类型2 数据名2, ..., 数据类型n 数据名n)
- 函数的具体实现步骤:函数的功能实现
main默认函数为:
int main(int argc, const char *argv[]){
// 写代码
}
函数的调用
语法:{返回值类型 变量名=}函数名(实参列表);
#include <stdio.h>
// 声明函数
int sum(int nums[], int size);
int main(){
int ns[] = {1,2,3,4};
int size = sizeof(ns) / sizeof(ns[0]);
printf("%d\n", sum(ns, size));
return 0;
}
int sum(int nums[], int size){
int result_num = 0;
for (int i=0; i<size; i++){
result_num += nums[i];
}
return result_num;
}
- 返回值类型:与函数的返回值一致
- 函数名:被使用的那个函数的名字
- 实参列表:与形参列表对应,位置、类型、数量要一模一样
- 主调函数:
- 调用别的函数的函数:上述代码中:main是sum的主调函数
- 被调函数:
- 上述代码中,sum为被调函数
函数的调用过程
- 把实参的值赋值给形参
- 执行被调函数中的语句代码
- 被调函数返回时,函数的表达式的值就是return后面的表达式的值
函数的数据传递
- 主调函数 --> 被调函数:传参
- 被调函数 --> 主调函数:返回值
- 主调函数 <-> 被调函数:指针,全局变量
函数的声明:
- 提前告知编译器有这么一个函数
- 因为编译器在变异代码的时候,是从上往下的。当被调函数在主调函数的后面的时候,就要声明。否则会找不到。
- 声明的时候可以省略形参名
// 声明函数 函数头;
注意:一个程序里面main函数有且只有一个,其他函数不限制
递归函数
是指在函数调用过程中,直接或者间接调用自身。
递归函数不会降低复杂度,只会增加复杂度
-
优点:
- 把复杂问题简单化
- 提高big
-
代码(计算1+2+3+...+n)
#include <stdio.h>
int calc(int);
int main(){
printf("%d\n", calc(100));
printf("%d\n", calc(1000));
return 0;
}
int calc(int n){
if (n == 1){
return 1;
}
return n + calc(n-1);
}
变量的作用域和生存期:
变量的作用域
- 全局变量
- 全局变量作用域:从定义到当前文件结束都可以使用
- 对于整个工程来说,在其他文件里使用,要加extern进行外部声明
- 如果全局变量使用static修饰的话,那么就只能在本文件使用
- 局部变量
- 从局部变量定义处开始到函数结束或者复合语句结束
- 不同作用域的两个变量,必定是两个不同且独立的内存空间。即使同名,也是独立的。遇到同名情况,会往上就近寻找。
变量的生存期
变量的生存周期,当变量过了他的生存期,其内存空间就会被释放掉
- 全局变量的生存期:
- 随进程持续性。即只要程序一运行,全局变量的内存就会被分配好,并且一直会存在,直到程序退出
- 局部变量的生存期:
- 普通局部变量:从定义处到他的函数结束或者复合语句结束
- 静态的局部变量:即使用了static进行修饰的局部变量。生存期从程序已运行就会分配内存,直到程序结束,并且初始化只会执行一次。
注意:我们可以通过花括号来确定一个变量的作用域,向下找右花括号。从定义处到向右花括号就是作用域范围。