函数
函数的概念
c语言的函数就是一个完成某项特定任务的一小段代码,这段代码有特殊写法和调用方法
C语⾔的程序其实是由⽆数个⼩的函数组合⽽成的,也可以说:⼀个⼤的计算任务可以分解成若⼲个较
⼩的函数(对应较⼩的任务)完成。同时⼀个函数如果能完成某项特定任务的话,这个函数也是可以
复⽤的,提升了开发软件的效率。
函数分为两类
- 库函数:可以直接使用的函数
- 自定义函数:自己设计的函数
库函数
库函数的定义
C语⾔标准中规定了C语⾔的各种语法规则,C语⾔并不提供库函数;C语⾔的国际标准ANSI C规定了⼀ 些常⽤的函数的标准,被称为标准库,那不同的编译器⼚商根据ANSI提供的C语⾔标准就给出了⼀系列 函数的实现。这些函数就被称为库函数。
各种编译器的标准库中提供了⼀系列的库函数,这些库函数根据功能的划分,都在不同的头⽂件中进
⾏了声明
库函数的使用
例子:sqrt
double sqrt(double f);
sqrt是计算一个数的平方根
double 表示sqrt函数的返回值类型是浮点型
sqrt是这个函数的函数名字
f是函数的参数,若是想调用这个函数需要传一个浮点型的值
调用一个库函数需要调用对应的头文件,比如sqrt对应的头文件就是#include<math.h>
自定义函数
自己定义一个函数,自己设计其中的功能,供自己使用
函数的语法形式
ret_type fun_name(形式参数)
{
函数体
}
- ret_type表示函数的返回值类型(所有基本类型都可以当返回值),如果不需要返回类型就void
- fun_name表式函数的名字,函数名字要尽量有意义,
- 形式参数也可以有多个,但是类型一定是一样的
- 函数的功能是在大括号实现的
函数的举例
计算两个数相加的过程
int Add(int a, int b)//设计一个返回值是整形类型的函数,名字为Add,里面的形式参数对应主函数里面的i,k
{
return a + b;//将a+b的值返回给Add
}
int main()
{
int i = 0;
int k = 0;
scanf("%d%d", &i, &k);//输入i,k的值
int r = Add(i, k);//调用i,k的值赋值给r
printf("%d", r);//输出r的值
return 0;
}
实际参数的值也可以是一个变量
比如:
写一个函数,输入一个数字,屏幕上打印相对应数量的*
void print(a)//返回类型为空,不需要返回任何值,函数名字为print,形参为a,对应下面的n
{
for (int i = 0;i <= a;i++)
{
printf("*");
}
}
int main()
{
int n = 0;
scanf("%d", &n);//输入n的值
print(n);//调用print函数,
return 0;
}
形参和实参
先写一个函数,求两个数的较大值,并输出出来
int Max(int i, int k)//函数定义中,括号里面的参数就叫形参
{
return (i > k ? i : k);
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
int r = Max(a, b);//函数调用时真实传递给函数的参数就是实参,也叫实际参数
printf("%d", r);
return 0;
}
实参
在上面代码中,主函数里面,调用Max函数时,传递给函数a,b的值为实参
形参
在函数定义时,括号里面的I,k就是形参
如果只定义了Max而不调用这个函数,Max函数中的i,k只是在形式上存在,也不会像内存申请空间,不是真实存在的,所以叫形参。
形参的实例化
形式参数只有在函数被调⽤的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化。
形参和实参的关系
int Add(int a, int b)
{
return a + b;
}
int main()
{
int i=20;
int k=50;
int r = Add(i, k);
printf("%d", r);
return 0;
}
可以发现,i,k向a,b传参的过程中虽然值没变但是地址变了,说明形参是重新开辟了一块内存空间。也就是形参其实是实参的一份儿临时拷贝。
return语句
- return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式
的结果。
-
return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况。
-
return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型。
-
return语句执⾏后,函数就彻底返回,后边的代码不再执⾏。
-
如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误
数组作为函数参数
数组传参的基本格式
设置一个数组,把里面的值都变成-1,并且打印出来
void init_arr(int arr[10], int sz)//arr后面的10可以省略,但[]不可以省略
{
int i = 0;
for (i = 0;i < sz;i++)
{
arr[i] = -1;//将数组的值初始化为-1
}
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0;i < sz;i++)
{
printf("%d", arr[i]);
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//设计一个数组
int sz = sizeof(arr) / sizeof(arr[0]);//计算数组的元素个数
print_arr(arr, sz);//先打印出原本的数组的值
init_arr(arr,sz);//数组初始化的过程,实参要包括数组名字和元素个数
print_arr(arr, sz);//打印初始化后的数组的值
return 0;
}
这⾥的init_arr函数要能够对数组内容进⾏设置,就得把数组作为参数传递给函数,同时函数内部在设
置数组每个元素的时候,也得遍历数组,需要知道数组的元素个数。所以我们需要给init_arr传递2个参
数,⼀个是数组名字,另外⼀个是数组的元素个数。仔细分析print_arr也是⼀样的,只有拿到了数组和元
素个数,才能遍历打印数组的每个元素。
数组传参的注意事项
-
函数的形式参数要和函数的实参个数匹配
-
函数的实参是数组,形参也是可以写成数组形式的
-
形参如果是⼀维数组,数组⼤⼩可以省略不写
-
形参如果是⼆维数组,⾏可以省略,但是列不能省略
-
数组传参,形参是不会创建新的数组的
-
形参操作的数组和实参的数组是同⼀个数组
二维数组作为函数参数
void print_arr(int arr[3][5], int i, int j)//参数接收数组大小,行数,列数
{
for (int a = 0;a < i;a++)//打印行
{
for (int b = 0;b < j;b++)//打印列
{
printf("%d", arr[a][b]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{5,6,9,8,5},{5,6,4,5,8} };//初始化二维数组
print_arr(arr, 3, 5);//将数组名,行数,列数传给参数
return 0;
}
函数的嵌套调用和链式访问
嵌套调用
嵌套调用就是函数之间可以互访访问,互相调用
例子实现
计算某年某月有多少天
思路:因为平年二月有28天,闰年二月有29天,所以我们要写一个函数判断是不是闰年,再写一个函数,如果是闰年的话在计算某月对应的天数
int is_run(int y)
{
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)//判断是不是闰年,闰年返回1,否则返回0
{
return 1;
}
else
{
return 0;
}
}
int run(int y, int m)
{
int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//创建一个数组,放各个月份对应的天数
int day = days[m];
if (is_run(y) && m == 2)//创建一个函数,判断是不是闰年,要是闰年并且是二月的话天数+1
{
day += 1;
}
return day;
}
int main()
{
int year = 0;
int mouth = 0;
scanf("%d%d", &year, &mouth);
int day=run(year, mouth);//创建一个函数,实参为year,mouth返回的值放到day
printf("%d", day);//打印day的值
return 0;
链式访问
将一个函数的返回值作为另一个函数的参数,就叫链式访问
int main()
{
size_t len = strlen("abcdef");
printf("zd",len);
return 0;
}
上述函数先计算出字符串长度在打印,但是,可以通过链式访问可以一步实现。
int main()
{
printf("%zd", strlen("abcdef"));
return 0;
}
将strlen(“abcdef”)作为printf的参数,然后printf再调用这个参数,这就叫链式访问。
### 链式访问
将一个函数的返回值作为另一个函数的参数,就叫链式访问
```c
int main()
{
size_t len = strlen("abcdef");
printf("zd",len);
return 0;
}
上述函数先计算出字符串长度在打印,但是,可以通过链式访问可以一步实现。
int main()
{
printf("%zd", strlen("abcdef"));
return 0;
}
将strlen(“abcdef”)作为printf的参数,然后printf再调用这个参数,这就叫链式访问。
‘’