1.函数
- 库函数
- 自定义函数
2.函数的参数
- 实际参数(实参)
- 形式参数(形参)
3.函数的调用
- 传值调用
- 传址调用
4.函数的嵌套调用和链式访问
- 嵌套调用
- 链式调用
5.函数的声明和定义
- 声明
- 定义
6.函数递归与迭代
- 递归
- 迭代
1.1 库函数
C语言基础库自己提供的一系列常用的库函数
头文件引用 #include<**>
#include<stdio.h>
int main()
{
printf("111");
return 0;
}
//结果:111
//printf 库函数
//#include<stdio.h> 头文件引用
两个查阅库函数的网站
1.2 自定义函数
由程序员自己设计的,与库函数一样的形式的函数
函数的组成
ret_type fun_name(para1,para2)
{
statement;
}
//ret_type 返回类型
(如果有类型,语句后需要+return,如果无类型void,语句后!+return。)
//fun_name 函数名
//para1,para2 函数参数
//statement 语句
#include<stdio.h>
int SUM(int a, int b)
{
return a + b;;
}
int main()
{
int x, y;
scanf_s("%d %d", &x, &y);
printf("%d", SUM(x, y));
return 0;
}
//结果:输入1 2 输出3
//SUM是自己定义的函数
//a,b为函数参数(形参)
//int有类型,return(返回) ret(这个值)
2.1 实际参数(实参)
1.真实传给函数的参数
2.实参可以是:常量,变量,表达式,函数等,注意:实参需要有确切的值,以便可以传递给形参。
2.2 形式参数(形参)
1.仅出现在函数内部中
2.形参仅在函数内部有效,函数调用结束时,形参变量则不能被使用
3.1 传值调用
形参是实参的一份临时拷贝
函数的形参和实参分别占用不同的内存块,所以改变形参的值对实参的值没有影响
使用场景:仅对实参进行操作,函数调用结束后,没有改变实参的值
#include<stdio.h>
int SUM(int a, int b)
{
return a + b;;
}
int main()
{
int x, y;
scanf_s("%d %d", &x, &y);
int num=SUM(x, y)//传值
printf("%d", num);
return 0;
}
//结果;输入1 2 输出3
//a,b为形参,x,y为实参
//当函数调用完,返回一个结果值num,实参x,y的值不发生改变
3.2传址调用
把实参的内存地址传递给形参,即形参和实参所占的内存块一样,所以改变形参的值会改变实参的值。
使用场景:对实参进行操作,函数调用结束后,改变实参的值
注意:使用传址调用,需要用指针来接收形参
#include<stdio.h>
void SWAP(int* pa, int* pb)
{
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main()
{
int x, y;
scanf_s("%d %d", &x, &y);
printf("使用函数前 %d %d\n", x, y);
SWAP(&x, &y);//传址
printf("使用函数后 %d %d",x,y);
return 0;
}
//结果 输入1 2 输出使用函数函数前 1 2,使用函数后 2 1
//pa,pb为形参,x,y为实参
//当函数调用完,无返回值,实参x,y的值发生改变(交换数字)
4.1函数的嵌套调用
函数可以根据需要进行相互调用,即在函数中使用函数
#include<stdio.h>
int main()
{
printf("111");
return 0;
}
//结果:111
//在主函数main中使用printf函数
4.2函数的链式访问
把一个函数的返回值作为另一个函数的参数
#include<stdio.h>
#include<string.h>
int main()
{
char arr [10] = "abcde";
printf("%d", strlen(arr));
return 0;
}
//结果:5
//把strlen函数的返回值当成是printf函数的参数
经典例题
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
//结果:4321
//前提条件:知道printf的返回值是输出的字符数量(打印在屏幕的一切),包括数字,字母,标志符号,空格,换行符等等
//最里面的printf打印43返回2,中间的printf打印2返回1,最外面的printf打印1----4321
5.1函数的声明
函数的声明一般出现在函数使用之前,即先声明后使用,而且一般放在头文件(有多个.c文件时)
函数声明的目的主要是让编译器知道有这样的一个函数(名字,参数,返回类型),但是这个函数可以不存在
int SUM(int a,int b)
int SUM(int,int)
//两种方法
//返回类型 函数名 参数1,2
5.2函数的定义
指函数的具体实现方式,交代函数的功能。
- 函数的声明一般在函数的定义之前,而函数定义在一定程度上有函数声明的作用。
1.如果函数定义在后,而调用函数在前时,必须要在调用语句之前进行声明(即函数定义放在主函数之后)
#include<stdio.h>
int SUM(int a, int b);//函数的声明
int main()
{
int x, y;
scanf_s("%d %d", &x, &y);
printf("%d", SUM(x,y));//函数的调用
return 0;
}
int SUM(int a, int b)//函数的定义(实现)
{
return a + b;
}
//在标准的c编译器环境下是不合法的,在GCC编译器环境下不会报错(vs,dev)
2.如果调用函数在定义之后,则可以不用单独声明(即函数定义放在主函数前面)
#include<stdio.h>
int SUM(int a, int b)
{
return a + b;
}
int main()
{
int x, y;
scanf_s("%d %d", &x, &y);
printf("%d", SUM(x,y));
return 0;
}
//注意:当项目很大,含有多个.c源文件时,把函数的定义放在一个.c源文件,把主函数放在另一个.c源文件,把函数声明放在.h头文件(习惯)
在每个源文件中都包含自己设置的头文件就可以不用再次声明函数了
6.1函数的递归
一个函数在自己的函数体内调用它自己本身
A函数不停调用A函数
递归函数必须有结束条件,每次递归调用之后越来越接近这个限制条件。
通常函数递归可以把原本复杂的问题转换为较为简单的问题,只需少量代码就可以解决多次重复计算
注意:递归太深容易造成堆区溢出
//最简单的函数递归(不标准,无结束条件)
#include<stdio.h>
int main()
{
printf("111");
main();
return 0;
}
//结果:无限打印111,直到程序崩溃
//用递归的方式来求n的阶乘
#include<stdio.h>
int factorial(int n)
{
if (n <= 1)
return 1;
else
return n *= factorial(n - 1);//调用函数自己本身
}
int main()
{
int num ;
scanf_s("%d", &num);
int ret = factorial(num);
printf("%d", ret);
return 0;
}
//结果:输入3 输出6
6.2函数的迭代
利用变量的初始值来推算变量的一个新值(代码的一部分循环)
A函数不停调用B函数
注意:迭代可以转换为递归,而递归不一定能转换为迭代
//用迭代的方式来求n的阶乘
#include<stdio.h>
int factorial(int n)
{
int i,j=1;
for (i = 1; i <= n; i++)//代码 部分实现循环
{
j *= i;
}
return j;
}
int main()
{
int num ;
scanf_s("%d", &num);
int ret = factorial(num);
printf("%d", ret);
return 0;
}
//结果:输入3 输出6