一,函数的概念
函数这个概念相信大家最早接触,是在数学当中,如一次函数:y=kx+b,其中k与b为常量,给出任意x的值就能够知道y的值。
在C语言当中也引入了函数(function)的概念,当然另一种翻译——子程序,会帮助我们有更好的理解。
C语言中的函数就是一个完成某项特定任务的一小串代码。这串代码是有特殊的写法和调用方法的。
C语言的程序其实是由无数个小的函数组合而成的,也可以说:一个大的计算任务可以分解成若干个较小的函数完成。同时一个函数如果能完成某项特定任务的话,这个函数也是可以复用的,这就大大提升了软件的开发效率。
在C语言中我们一般会遇见两种函数:
二,库函数
1.标准库和头文件
C语言标准中规定了C语言的各种语法规则,但C语言本身并不提供库函数;C语言的国际标准ANSI规定了一些常用的函数标准,被称为标准库;不同的编译器厂商又根据ANSI提供的标准库给出了一系列函数的实现,这些函数就被成为库函数。
在有了库函数之后,一些常见的功能便不用程序员自己进行实现,函数是现成的,只需要学会就能直接进行使用,不仅质量和执行效率都更有保证,且在一定程度上大幅提升了开发效率。
各种编译器的标准库中提供了一系列的库函数,这些库函数根据功能的划分,都在头文件中进行了声明。
2.库函数的使用方法
库函数的学习和查看有相当多的网站与工具,可以自行在百度上进行查找学习;如:
C/C++官方链接:https://zh.cppreference.com/w/c/header
cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
举例:sqrt
i.功能
ii.头文件包含
![](https://img-blog.csdnimg.cn/d127686f2eef49689bdc45b5b6013147.png)
iii.实践
![](https://img-blog.csdnimg.cn/9f739add33c24070846120e79d87e1db.png)
iiii.库函数文档的一般格式
![](https://img-blog.csdnimg.cn/cc3b10e625564a9ea34019a233cab683.png)
三,自定义函数
C语言中,除了常用到的,我们还可以为了方便自己程序的书写而自己创造函数,也就是自定义函数,这也就为我们写代码带来了更多的创造性。
数的语法形式函
![](https://img-blog.csdnimg.cn/308917a547474616ae7b02a5a272d80b.png)
![](https://img-blog.csdnimg.cn/1585db83a45643cfb8b3801ad859b63a.png)
![](https://img-blog.csdnimg.cn/ad127f4adec54e60a74b43ce4519cbfe.png)
![](https://img-blog.csdnimg.cn/6b0bee699c414f1fb5cf806a76873a45.png)
![](https://img-blog.csdnimg.cn/479d849947cb4651a1a6383669091530.png)
![](https://img-blog.csdnimg.cn/89ad5806365341e9bfb6daeacfdc2bd2.png)
四,return语句
相信大家对return定不会感到陌生,都知道它在返回值时会使用到,但却没有细微的去了解过return语句的注意点,接下来就让我来为大家介绍一下
• return后面可以是一个数值,也可以是一个表达式,如果后面是表达式,则会执行该表达式,并返回表达式执行的结果。
• return后面也可以什么都没有,直接写return;这种情况常用于函数类型是viod的情况。
五,数组做函数参数
我们在明白函数是如何传递参数后,我们又会遇到新的问题,那就是在传递参数时碰到将数组作为参数传递给函数的情况,在函数内部对数组进行操作。
接下来,我们用代码大致来实现一下该操作。
先写出主函数表达一下我们大概的构思
这里我们所需要的set_arr函数要能够对数组进行设置,所以就得把数组作为参数传递给函数,同时在函数内部设置数组每个元素的时候,也得遍历数组,需要知道数组的元素个数,所以我们需要给set_arr函数传递两个参数,一个是数组,另一个则是数组的元素个数。
此外再对printf_arr函数进行分析,发现创建该函数需要满足的条件同set_arr函数相似,只有拿到了数组和数组的元素个数,才能遍历打印打印数组的每个元素。
知道了传递的参数后我们便可以此设计函数了。
在设计之前,我们先了解一下数组传参时的几个重要知识点
于是我们依照此处知识点写上我们上方所需要的函数
整个代码:
打印结果:
六,嵌套调用和链式访问
1.嵌套调用
嵌套调用就是各个函数之间的互相联系与利用,也就是一个函数可以写入另一个函数当中,也正是函数之间的有效调用,才使得相对较大型的程序得以较为简单的开发出来
假设:我们需要写一个程序来计算某年某月有多少天
我们先对题目进行分析:
1.我们需要定义两个变量来实现输入年份和月份
2.每年的每个月有多少天是固定的,但闰年的2月份是个例外
3.我们设想写一个函数来判断该年份是否为闰年,再写一个函数来判断该输入的年月对应的输出天数
4.我们定义一个数组来装下12个月份的各月份的天数,以月份为下标的方式来实现查找功能
首先我们根据构思写上主函数
然后我们根据逻辑关系写上is_leap_year函数来判断输入年份是否为闰年
随后继续根据逻辑顺序写上Day函数来帮我们计算天数
至此,我们整个题目要求的代码便大功告成了,让我们来瞅瞅吧
再让我们来看看打印结果
这一串代码不仅完成了一个独立的功能,而且还反应不少函数的调用:
2.链式访问
链式访问就是将一个函数的返回值作为另一个函数的参数,像链条一样将函数串起来,就是函数的来链式访问。
如:
如果我们要用链式访问打印上述代码的话,我们便只需要将strlen的返回值作为printf函数的参数便可以了
明白了上述知识点后,再让我们来试着解读一下这串代码
很显然,这串代码将printf函数的返回值作为了printf函数的参数,所以在我们解读这串代码前得先明白printf函数的返回值是什么
原来,printf函数的返回值就是打印在屏幕上的字符个数
由此我们便可以试着解读这串代码了
1.最内层的printf函数在屏幕上打印了43,含有两个数字,所以最内层的printf函数返回值为2;
2.第二个printf函数将最内层printf函数的返回值“2”作为参数,故在屏幕上打印数字2这一个字符,所以第二个printf函数的返回值为1;
3.第一个printf函数将第二个printf函数的返回值1作为参数,在屏幕上打印数字1;
4.在清楚每个printf函数打印的值后,根据程序运行顺序分析出首先打印43,其次打印2,最后打印1。于是我们便得到了这串代码的打印结果4321。
七,函数的声明和定义
1.单个文件
函数的调用满足先声明,后使用;函数的定义也是一种特殊的声明,所以函数定义放在调用之前也是可行的。
具体什么意思?让我们通过以下例子来进行理解
该情况为函数声明置于函数调用前
而当函数调用置于函数声明后时,编译器就会报出这样的警告
这是因为程序是逐行向下运行的,当运行到函数调用那行时,前方并没有对该函数进行声明,所以才会报出警告;解决问题则需再前方对该函数进行声明即可。
如:is_leap_year(int year),像这样交代清楚函数类型,函数名,函数的参数即可。
2.多个文件
当面对大型程序时,往往牵扯的代码量较大,这时候我们便会把一个程序拆分为多个文件进行设计;而这个时候,函数的声明,类型的声明我们就会放在.h为后缀的头文件中,函数的实现放在.c为后缀的源文件中。
我们以加法函数和运行举例:
在完成加法函数板块后我们又该如何使用呢?
原来我们只需要像使用库函数一样,包含该函数的头文件即可。
3.static和extern
i.作用域和生命周期
ii.extern
C语言中extern用来声明外部符号
iii.static
static是静态的意思,有以下几点作用:
• 修饰全局变量
• 修饰局部变量
• 修饰函数
static修饰局部变量
对比两串代码,我们发现在static修饰局部变量t后打印结果发生了明显的改变,由原来的五次循环,每次循环值不变变为了五次循环,每次循环值+1
这是因为:
static修饰全局变量
extern用来声明外部符号,如果文件A定义了符号,文件B想要使用,便可以使用extern来进行声明;但当不同文件的全局变量被static修饰后,即使使用extern进行声明,也不能正常使用。
得出结论:
static修饰函数
由此看来,static无论是修饰全局变量还是函数,在不同文件中被修饰后都无法使用extern声明使用。
所以当存在一个函数只想在所在的源文件内部使用,不想被其它源文件使用,就可以使用static修饰。