文章目录
- 函数
- 函数的定义与声明
- 局部变量和全局变量、静态变量
- 静态变量和动态变量
- 函数的值传递
- 函数参数的地址传值
- 函数的嵌套使用
- 函数的递归调用
函数
函数的定义与声明
函数的概念:函数是C语言项目的基本组成单位。实现一个功能可以封装一个函数来实现。定义函数的时候一切以功能为目的,根据功能去定函数的参数和返回值。
函数的定义
函数定义的格式:
函数的返回值类型 函数名(形参列表)
{
代码块;
}
注意:
- 函数的返回值类型,可以是学过的int、char、float、double以及void,还可以是以后要学习的类型;它的作用:表示函数执行完之后,可以得到一个什么类型的值。
- return 返回出一个具体值(void类型的返回值可以没有return)。
- 函数名:标识符(符合用户自定义标识符)、见名知意
- 有指定参数时,要指定参数的类型、名字;参数可以是一个、多个,也可以没有。
- 不能在定义函数时,在函数首部小括号后直接跟分号。
- 指定函数所完成的功能,也就是规定函数要完成什么操作, 函数是做什么。
- 函数体可以没有语句,但不能没有花括号。
- 在定义函数的里面,不能再定义一个函数。
- 例1:定义一个打印九九乘法表的函数并调用
#include<stdio.h>
//定义一个函数,打印一个九九乘法表
void printMul() //void 定义一个返回值为空的函数
{
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
printf("%dx%d=%d\t", j, i, i*j);
}
printf("\n");
}
}
int main()
{
printMul();
return 0;
}
注意:当main
函数写在调用的函数之前时,程序运行会报错。因为程序是从上到下运行,当运行到main函数中时找不到你所调用的printMul()
函数,则会报错。这时,我们可以进行函数声明来解决这个问题。
函数声明语句的一般格式:
函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2,……);
也就是相当于把函数头前置
#include<stdio.h>
void printMul(); //函数的返回值类型 函数名(形参列表);
int main()
{
printMul();
return 0;
}
//定义一个函数,打印一个九九乘法表
void printMul() //void 定义一个返回值为空的函数
{
.....
}
- 例2:函数的返回值类型说明,函数的返回值类型必须跟函数类型一致,否则就会出现错误。例如我想定义一个返回值为整型的函数
- 若返回值为双精度浮点型,则会出现数据丢失,因为只返回整型数据
局部变量和全局变量、静态变量
什么是局部变量 ?
局部变量是在函数中定义的普通变量(没有任何的修饰),以及在函数开头定义的形参。
局部变量的作用范围:从定义开始,往下的作用域;出了作用域就不能使用。函数开头定义的变量,在该函数范围内有效。
什么是全局变量?
全局变量:函数外或全局空间定义的变量
全局变量的作用范围:从定义开始往下,在本文件内所有的地方都可以使用。
全局变量在程序结束的时候,会被释放。
#include<stdio.h>
int a = 10; //定义一个全局变量
void func1()
{
int a = 30;
printf("func1函数中:a=%d\n", a);
}
void func2()
{
printf("func3函数中:a=%d\n", a);
}
int main()
{
func1();
func2();
return 0;
}
静态变量和动态变量
程序中所定义的变量默认是动态局部变量(auto
)。
在定义变量前加一个static
可定义一个静态局部变量。
静态变量在程序开始后定义,结束前才会被释放,所以其生命周期比较长,在函数调用中只会被定义一次,不会被定义多次,当再次执行到定义语句时,其值不会被重置(初始化),会保留上次改变的值。
void func2()
{
static int c = 10; //静态变量 c会被锁住,让c不会被释放
int b = 10;
b++; c++;
printf("b=%d\tc=%d\n", b, c);
}
int main(void) //有void表示不会有任何实参传过来,如果有就会报错
{
for (int i = 0; i < 3; i++)
{
func2();
}
return 0;
}
函数的值传递
注意:形参不会改变实参的值,实参传值给形参,值是一个单向传递。
函数参数的地址传值
fun函数的形参是如何接收传输数据——地址?
(1)先得到数据的地址,然后传给函数。
(2)访问定义函数的里的这个地址的值
如何定义一个接收地址的变量?
能存地址的变量:指针变量
指针变量的定义: 数据类型 *指针名
数据类型:用指针存的什么类型的地址
指针名:符合标识符命名规则和命名规范
*
—— 取值运算符、解引用;通过地址做解引用找到值
函数的嵌套使用
函数的定义时相互平行、独立的,在定义函数时,一个函数内不能再定义另一个函数,也就是说,函数不能嵌套定义。
但是函数可以嵌套调用,也就是再调用一个函数的过程中,又调用另一个函数。
函数的递归调用
函数的递归:在一个函数中,函数重复的调用自己。
在函数调用的时候,函数会入栈。
- 注意以上结果,当我们调换两个语句时,会有不一样的结果
过程分析
- 函数递归调用经典例子:斐波那契数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)在现代物理、准晶体结构、化学等领域,斐波那契数列都有直接的应用,为此,美国数学会从 1963 年起出版了以《斐波那契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
int func5(int n)
{
if (n > 2)
{
return func5(n - 1) + func5(n - 2);
}
else if (n == 1 || n == 2)
{
return 1;
}
}
int main(void) //有void表示不会有任何实参传过来,如果有就会报错
{
printf("%d\n", func5(4));
return 0;
}