目录
一.函数的概念
C语言中的函数就是一个完成某项特定任务的一小段代码。
特点:
- 一小段代码。
- 完成某项特定任务。
好处:
- 可拆分任务。
- 可重复利用,提高开发效率。
二.函数的分类
两类函数:
- 库函数(现成的、可直接使用的函数)
- 自定义函数(根据需要,自己设计和创造的函数)
1.库函数
1.1.标准库和头文件
C语言提供了语法规则和一些库函数的信息(如,printf-名字-参数-返回类型···),但不提供库函数。C语言编译器厂商根据规定来实现这些函数。
各种编译器的标准库中提供了一系列的库函数,这些库函数根据功能划分,都在不同的头文件中进行了声明。
库函数相关头文件:https://zh.cppreference.com/w/c/header
1.2.库函数的使用方法
库函数的学习和查看工具很多,按需自取哈:
C/C++官方的链接:https://zh.cppreference.com/w/c/header
cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
例如:sqrt
double sqrt (double x);
// sqrt 是函数名
// x 是函数的参数,表示调用sqrt函数需要传递一个double类型的值
// double 是返回值类型
1.2.1.功能
计算算术平方根
1.2.2.头文件
<math.h>
1.2.3.实践
#include<stdio.h>
#include<math.h>
int main()
{
double a = 16.0;
double b = sqrt(a);
printf("%lf\n", b);
return 0;
}
运行结果:
2.自定义函数
自定义函数一般比库函数更加重要,给了程序员写代码更多的创造性。
2.1.函数的语法格式
其实自定义导函数和库函数是一样的,形式如下:
ret_type fun_name(形式参数) //如,double sqrt(doouble x)
{
函数体
}
// ret_type 是函数返回类型
// fun_name 是函数名
//()里的是形式参数
// {} 里的是函数体(描述的是函数完成任务的过程)
我们可以把函数想象成一个工厂,参数为原材料,输入原材料(即参数)后,经过工厂(即函数)的加工,输出产品(即计算结果)。
注意:
- ret_type 是用来表示函数计算结果的类型,有时候返回类型可以是 void,表示什么都不返回。
- 函数的参数也可以是void,明确表示函数没有参数。如果有参数,要交代清楚参数的类型和名字以及参数的个数。
- fun_name是为了方便参数使用,但尽量要根据函数的功能取一些有意义的名字。
2.2.函数的举例
例,写一个加法函数,完成2个整型变量的加法操作。
//不创建函数时
#include<stdio.h>
int main()
{
int a = 0, b = 0;
scanf("%d %d", &a, &b);
printf("%d\n", a + b);
return 0;
}
//
//
//创建一个名为Add的加法函数
#include<stdio.h>
int Add(int x, int y) //x,y为两个参数;Add为函数名;返回整形类型
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0, b = 0;
scanf("%d %d", &a, &b);
int sum = Add(a, b); //a,b是Add函数接收的2个整形类型的参数
printf("%d", sum);
return 0;
}
Add函数也可简化为:
int Add(int x, int y)
{
return x + y;
}
注意:参数的参数部分需要交代清楚参数个数、每个参数的类型和参数的名字。
三 .形参和实参
1.概念
- 实参:函数调用时传给函数的参数。
- 形参:函数定义中的参数。(若只定义了函数,而没有调用,则函数的参数x,y只是形式上存在的,不会向内存申请空间,不会真实存在,所以叫形式参数。)
- 形式的实例化:形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才会向内存申请空间,这个过程就叫形式的实例化。
2.形参与实参的关系
我们调试的时候可以发现,x和y确实得到了a和b的值,但是x和y的地址与x和y的地址是不一样的,所以我们可以理解为形参是实参的一份临时拷贝。
四.return语句
在函数的设计中,经常会出现return语句,这里说一下注意事项:
- return后边可以是一个数值,也可以是一个表达式。如果是表达式则先执行表达式,再返回表达式的结果。
- return后边也可以什么都没有,直接写 return;这种写法适合函数返回类型是void的情况(即无返需返回)。
- return返回的值和函数返回类型不一致,系统会自动将返回的值隐式转换为函数的返回类型。
- return语句执行后,函数就彻底返回,后边的代码就不再执行。(break是结束循环)
- 如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误。
五.数组做函数参数
1.实例
写一个函数对一个整数数组的内容全部重置为-1,再写一个函数打印数组的内容。
//将数组内容重置为-1的函数set_arr的创建
void set_arr(int arr[], int sz)
//一维数组的数组大小可省略不写;二维数组只可省略行,列不可省略。
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = -1;
}
}
//
//打印数组函数print_arr的创建
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
//
//主函数
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10}; //形参和实参的名字可以一样
int sz = sizeof(arr) / sizeof(arr[0]);
set_arr(arr,sz);
print_arr(arr,sz);
//形参个数要与实参个数匹配
//数组传参,形参不会创建新的数组。形参和实参操作的数组是同一个。(特殊)
return 0;
}
2.注意
- 数组传参写的是数组名。(不带【】)
- 形参写的也是数组形式,并且写的时候可以省略元素个数。(仅限一维数组)
- 数组传参后,形参的数组和实参的数组是同一块空间,改变形参数组就是在改变实参数组。
形参数组和实参数组是同一块空间
六.嵌套调用和链式访问
1.嵌套调用
各个函数可以像乐高零件一样,相互无缝配合,组建成更大型的程序。他们之间的互相调用就是嵌套调用。
实例:
假设我们需要计算某年某月有多少天。
若要函数实现,可以设计2个函数:
- is_leap_year():根据年份确定是否为闰年
- get_days_of_month():根据月计算这个月的天数
#include<stdio.h>
int is_leap_year(int y)
//能被4整除并且不能被100整除,或能被400整除
{
if (((y % 4 == 0) && (y & 100 != 0)) || (y % 400 == 0))
return 1;
//是闰年
else
return 0;
//不是闰年
}
int get_days_of_month(int y, int m)
{
int days[] = { 0,31,28,31,30,31,30,31,31,31,30,31,30,31 };
// 下标 : 0 1 2 3 4 5 6 7 8 9 10 11 12 13
int day = days[m];
//几月刚好对应数字几
if (is_leap_year(y) && m == 2) //调用了is_leap_year函数
//是闰年,且是2月
day = day + 1;
//则2月为28+1=29天
return day;
}
int main()
{
int year = 0, month = 0;
scanf("%d %d", &year, &month);//调用了scanf函数
int d = get_days_of_month(year, month);//调用了get_days_of_month函数
printf("%d", d);//调用了printf函数
return 0;
}
2.链式访问
将一个函数的返回值作为另一个函数的参数,像链条一样将函数串起来就是函数的链式访问。
例如:
#include<stdio.h>
#include<string.h>
int main()
{
int len = strlen("abcdef");
printf("%zd\n", len);
return 0;
}
也可将strlen的返回值直接作为printf函数的参数,形成链式访问:
#include<stdio.h>
#include<string.h>
int main()
{
printf("%zd\n", strlen("abcdef"));
return 0;
}
本次分享已到尾声,期待下次与大家的分享~