第六章:函数
文章目录
- 第六章:函数
- 1. 库函数
- 2. 自定义函数
- 2.1 形参和实参
- 2.2 return 语句
- 2.3 数组做函数参数
- 3. 嵌套调用和链式访问
- 3.1 嵌套调用
- 3.2 链式访问
- 4. 函数声明和定义
- 4.1 单个文件
- 4.2 多个文件
- 4.3 关键字使用
- 4.3.1 extern
- 4.3.2 static
- 声明
C 语言中的函数就是一个完成某项特定任务的一小段代码。
1. 库函数
不同编译器提供的一系列函数的实现,就被称为库函数。这些库函数根据功能的划分,都在不同的头文件中进行声明。
库函数相关头文件:C Standard Library headers - cppreference.com
2. 自定义函数
语法形式
函数返回类型 函数名(形式参数){}2.1 形参和实参
- 形参:在自定义函数的括号中写的参数,称为形式参数
- 实参:真是传递给函数的参数
- 函数的形式参数要和和实参个数匹配
只有在函数被调用的过程中存放实参传递过来的值,才会向内存申请空间
加法函数,完成两个整形变量的加法操作:
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdbool.h>//第六章:函数//此时是形参,在不调用此函数时,不会分配内存空间,//当调用函数时,形参便会分配内存空间(和实参各自有独立的空间)intadd(inta,intb){returna+b;//将a+b的值返回出去}intmain(){inta=0;intb=0;intc=add(a,b);//调用函数,将变量传递进去,此时是实参scanf("%d",&c);printf("两个数之和是:%d",c);return0;}2.2 return 语句
- return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式 的结果。
- return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况。
- return语句执⾏后,函数就彻底返回,后边的代码不再执⾏。
- return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型。
- 如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误。
- 函数的返回类型如果不写,编译器会默认函数的返回类型是int。
- 函数写了返回类型,但是函数中没有使⽤return返回值,那么函数的返回值是未知的。
2.3 数组做函数参数
- 函数的实参是数组,形参也是可以写成数组形式的
- 形参如果是⼀维数组,数组⼤⼩可以省略不写
- 形参如果是⼆维数组,⾏可以省略,但是列不能省略
- 数组传参,形参是不会创建新的数组的
- 形参操作的数组和实参的数组是同⼀个数组
写一个函数将一个整形数组的内容,全部置为 -1,再写一个函数打印数组内容
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdbool.h>//数组做函数参数,数组的实参和形参是同一块内存空间//将数组内容全部置换为 -1voidset_arr(intarr[],intsz)//此时不设置长度,根据传过来的大小底层自动推断{for(inti=0;i<sz;i++){arr[i]=-1;}}//打印数组voidprint_arr(intarr[],intsz){for(inti=0;i<sz;i++){printf("%d ",arr[i]);}}intmain(){//定义数组intarr[]={1,2,3,4,5,6,7,8,9,10};//计算数组长度intsz=sizeof(arr)/sizeof(arr[0]);//调用置换数组函数set_arr(arr,sz);//调用打印数组函数print_arr(arr,sz);return0;}3. 嵌套调用和链式访问
3.1 嵌套调用
函数之间的互相调用称为嵌套调用。
实现计算某年某月有多少天:
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdbool.h>//嵌套调用//定义函数判断是否为闰年boolis_leap_year(intyear){if((year%4==0&&year%100!=0)||year%400==0){returntrue;}returnfalse;}//定义函数计算某年某月有多少天intget_days(intyear,intmonth){// 0 1 2 3 4 5 6 7 8 9 10 11 12intdays[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//前面补0,方便月份和下标对应if(is_leap_year(year)&&month==2)//嵌套调用判断是否是闰年和2月{days[month]+=1;//如果是闰年2月,则天数加1returndays[month];}returndays[month];//不是闰年,则直接返回对应月份的天数}intmain(){intyear=0;intmonth=0;scanf("%d%d",&year,&month);intdays=get_days(year,month);printf("%d年%d月有%d天\n",year,month,days);return0;}3.2 链式访问
谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数 的链式访问
//链式访问#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>intmain(){//printf的返回值是输出字符的个数,包括换行符和空格//输出 43 3 2printf("%d ",printf("%d ",printf("%d ",43)));return0;}4. 函数声明和定义
4.1 单个文件
当我们将自定义的函数放在 main 函数后,也就是调用此函数之后,需要在函数调用前声明一下此函数。函数的调用要满足先声明后使用,函数的定义是一种特殊的声明。
- 函数声明:函数返回类型 函数名(函数参数)
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdbool.h>boolis_leap_year(intyear);//函数声明intmain(){intyear=0;intmonth=0;scanf("%d%d",&year,&month);intdays=get_days(year,month);printf("%d年%d月有%d天\n",year,month,days);return0;}//定义函数判断是否为闰年boolis_leap_year(intyear){if((year%4==0&&year%100!=0)||year%400==0){returntrue;}returnfalse;}4.2 多个文件
函数的声明和类型的声明放在头文件中 (.h) ,函数的实现放在其他源文件中 (.c) ,此时 main 函数所在的源文件要包括自定义的头文件。
add.h
#pragmaonce//头文件用于声明函数、类、变量等,防止重复包含intadd(inta,intb);add.c
#define_CRT_SECURE_NO_WARNINGS//函数的定义intadd(inta,intb){//将a+b的值返回出去returna+b;}test.c
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>//包含自定义头文件,注意使用双引号#include"add.h"intmain(){inta=0;intb=0;scanf("%d%d",&a,&b);intc=add(a,b);printf("和是:%d\n",c);}4.3 关键字使用
作用域:一段程序中所用到的名字并不是总有效,可用性的代码范围称为作用域
- 局部变量:变量所在的局部范围
- 全局变量:整个项目
生命周期:变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段
- 局部变量:进入作用域变量创建,生命周期开始,出作用域生命周期结束
- 全局变量:整个程序的声明周期
4.3.1 extern
用于声明外部符号,如果一个全局的符号在A文件中定义,在B文件中想使用,就需要使用extern进行声明。
4.3.2 static
修饰局部变量
static 修饰局部变量改变了变量的⽣命周期,⽣命周期改变的本质是改变了变量的存储类型,本来⼀个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。存储在静态区的变量和全局变量是⼀样的,⽣命周期就和程序的⽣命周期⼀样了,只有程序结束,变量才销毁,内存才 回收。但是作用域不变的。
修饰全局变量或函数
⼀个全局变量被static修饰,使得这个全局变量只能在本源⽂件内使⽤,不能在其他源⽂件内使⽤。 本质原因是全局变量默认是具有外部链接属性的,在外部的⽂件中想使⽤,只要适当的声明就可以使⽤;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在⾃⼰所在的源⽂件内部使⽤了,其他源⽂件,即使声明了,也是无法正常使⽤的。函数同理
test2.c
#define_CRT_SECURE_NO_WARNINGS//定义全局变量//全局变量默认具有链接属性,其他文件可以通过extern进行访问//如果此时加上static,则变为内部链接属性,其他源文件无法访问//函数原理同上intnum=10;test.c
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>//static 和 extern关键字的使用voidtest();//函数声明externintnum;//声明外部变量intmain(){for(inti=0;i<5;i++){test();}printf("num = %d\n",num);return0;}voidtest(){//静态变量,只初始化一次(在程序编译时),仅改变生命周期,生命周期为整个程序运行期间//如果不加入static关键字,则每次调用变量时,变量都会重新初始化,即局部变量staticinta=0;a++;printf("%d\n",a);}声明
本文是在鹏哥 C 语言集训营学习过程中所记录的学习笔记,梳理了核心知识点,同时也记录了本人实操验证的代码案例,供后续学习复盘使用。