1. 函数概念
函数(子程序):完成某项特定任务的一小段代码。
功能:一个大任务分为多个小任务(函数)来完成,当某个小任务需要多次进行或多个任务间需要复合完成时,函数可以提高程序开发效率
C语言中函数分为两类:库函数和自定义函数。
2.库函数
2.1 标准库
C语言并不提供标准库,而是由C语言的国际标准ANSI规定了一些常用函数的标准,称为标准库,之后由不同的编译器厂商根据标准实现这些函数,称为库函数。根据功能划分,这些库函数都在不同头文件中进行了声明。
2.2 头文件
库函数相关头文件:
可以根据链接中的库函数文档,来学习库函数的使用
3.自定义函数
3.1 函数语法
函数的基本语法:
返回类型 函数名(形式参数列表){};
{}中的是函数体,用以实现函数的功能。
返回类型是调用函数后返回的数据的类型。
3.2 函数举例
通过自己实现一个简单的加法函数:
确定函数功能:在传入两个整型的参数后,返回两者之和。
所以函数接受两个整型类型的参数,(int x1,int x2),返回类型为 int。
注意,函数名没有具体要求,除C语言保留的关键字和C语言的命名规则之外,可以任意取名,但根据函数功能取名,便于他人阅读和理解代码。
4.实参和形参
实参:调用函数时传入的参数,上文中的x1和x2即为实参。
形参:函数定义句块中,Add后括号里的int x1,int x2即为形式参数。当函数调用时,形参才会向内存申请空间,用以储存实参传入的值,与实参的空间位置并不相同(浅拷贝),只是实参的一份临时拷贝,在函数调用完后便会及进行空间销毁。
5.return语句
1. 根据函数功能,return后接相应的数据,可以是值或表达式,若是表达式,会将运算结果返回。
2. 当return后不接数据,即return ;时,返回类型为void,表示无需返回。
3. return后接的值与返回类型不同时,对返回值进行相应的类型转化,变为对应的类型
4. return语句执行后,整个函数调用结束,之后的语句也不会再执行。
6. 数组传参
我们知道函数中的一份形参只能接受一份数据,但如果传入的是数组,结果是怎么样的?
数组的传参形式:
函数名(数组名);
如果要对数组进行遍历,还需要传入数组的元素个数,避免访问数组之外的元素。
那么应该如何定义含数组参数函数?
如下:
返回类型 函数名(元素类型 形参名[元素个数]...)
{
}
形参的类型应与数组类型相同,即 元素类型 [元素个数]
例子:
注意:
1. 形参数组的元素个数可以选择不进行写入(一维数组),否则个数必须与原数组的相同。
2. 二维数组可以选择对行数省略,但列数不可以省略
3. 形参实际接受的是数组的地址,操纵的元素与数组中的相同
7. 嵌套调用和链式访问
7.1 嵌套调用
在介绍函数功能时,我们谈到某些任务可以由其他小的任务复合完成,而在函数中也是能够调用其他函数的,也叫嵌套调用:
如上图所示,我们在print_arr函数中调用mod_arr函数,用以修改数组的值
7.2 链式访问
链式访问:将一个函数的返回值作为另一个函数的参数
例如,我们知道strlen函数可以用来计算字符串的长度,我们可以利用print函数将strlen的返回值打印出来:
8. 函数的声明与定义
8.1 单个文件
在创建一个小程序的时候,我们通常直接将函数的声明与定义写入同一个文件
函数声明:
图片中顶部的两行代码就是函数声明,也就是函数定义除去函数体部分,当然声明时参数部分的变量名也可以省略。
由于编译器是逐行执行的,倘若将函数定义放在函数调用之后,且之前缺少函数声明,编译器就会报错。而在之前加入函数声明后,向编译器声明函数的存在,编译器就会继续向下查找函数定义的存在。
注:函数定义也是一种特殊的函数声明
8.2 多个文件
在以后创建大程序时,为了代码的简洁性和方便查看代码,我们通常根据程序功能,将代码放在不同的文件中
例如,函数的声明和类型的声明放在头文件中,他们的实现放在源文件里
8.3 static和extern
static:静态的意思
8.3.1 修饰局部变量
改变局部变量的生命周期
与之前函数中创建的变量不同,经过static修饰后,变量的生命周期被改变,在函数结束后不被销毁,其本质是改变了数据的存储类型,由栈区变为了静态区,生命周期与程序的生命周期相同,但变量的作用域没有发生改变。
注意:static的修饰语句只会进行一次
8.3.2 修饰全局变量和函数
全局变量或函数被static修饰后,只能在本源文件中使用,由外部连接属性变为了内部连接属性
示例:
这里我们利用一个关键字extern,用以声明外部符号。当我们引用外部文件中未经修饰的数据时,可以正常使用。
当数据被修饰时,我们用extern声明后依旧报错,说明其的外部连接属性变为了内部连接属性
待续——