函数
- 函数是完成某项功能的程序模块(代码);
- C程序主要是由函数组成的,函数也是C程序实现模块化设计的主要途径。
- 函数的分类:
- 用户角度:
- 标准库函数
- 用户自定义函数 **
- 标准库函数
- 函数形式
- 有参函数
- 无参函数
- 有参函数
- 主调函数:主动调用某函数的函数;
- 被调函数:被调用的函数;
- 用户角度:
- 函数的优点:
- 可以减少重复性代码;
- 实现C程序的模块化设计;
- 可以减少重复性代码;
- 怎么定义函数?
- 格式:返回值类型 函数名(参数列表);
- {
- 函数体代码;
- 函数体代码;
- }
- 例子: int min(int a,int b)
- { return a
- 注意:如果省略函数的类型标识符,则默认为int 型
- {
- 形式参数是用来接收主调函数传输过来的数据。
- 格式:返回值类型 函数名(参数列表);
- 定义空函数
- 类型标识符 函数名()
- {}
- 调用此函数时,什么都不做。常用来在准备扩充功能的地方先写一个空函数,占位。
- 调用此函数时,什么都不做。常用来在准备扩充功能的地方先写一个空函数,占位。
- 类型标识符 函数名()
- 定义函数的注意事项:
- 函数类型标识符变量类型说明符相同,它表示返回的函数值的类型。
- 在C语言中还可以定义无类型(即void类型)的函数,这种函数不返回函数值,只是完成某种功能。
- 如果省略函数的类型标识符,则默认为是int型。
- 函数中返回语句的形式为 return(表达式);或 return 表达式;其作用是将表达式的值作为函数值返回给调用函数。其中表达式的类型应与函数返回值类型一致。
- 如果形参表中有多个形参,即使它们的类型是相同的,在形参表中也只能逐个进行说明。
- 如果”形参表列”中有多个形式参数,则它们之间要用”,”分隔。
- 一个完整C程序中的所有函数可以放在一个文件中,也可以放在 多个文件中。
- 函数类型标识符变量类型说明符相同,它表示返回的函数值的类型。
- 函数调用的一般形式:
- 函数名(实参表列)
- 函数调用方式
- 
- 函数名(实参表列)
- 函数参数和函数的值:
- 定义函数时,函数名后括号中的变量称为形式参数,即形参。
- 在主函数中调动函数时,函数名后括号中的表达式称为实际参数,简称实参。
- 函数调用时才给形参分配存储空间,且调用结束后所占空间立即释放。
- 形式参数(形参):函数定义时指定的参数。
- 实际参数(实参):函数调用时指定的参数。
- 形参在函数未被调用前是不开辟内存空间的,只有当函数被调用时,系统才会为形参开辟内存空间,用于接收实际的数据。
- 值传递|单向传递:在C语言中,实参向形参的数据传递是“值传递”,是单向传递,即只由实参传给形参,而不能由形参传回来给实参。在内存中,实参、形参占不同的存储单元,因此形参值的改变不会影响实参值。
- 形参在函数未被调用前是不开辟内存空间的,只有当函数被调用时,系统才会为形参开辟内存空间,用于接收实际的数据。
- 函数调用时才给形参分配存储空间,且调用结束后所占空间立即释放。
- 定义函数时,函数名后括号中的变量称为形式参数,即形参。
- 函数原型声明的两种形式:
- 1.函数类型 函数名(形参类型1 形参名1,形参类型2 形参名2,…);
- 各“形参名”可以是任意的,可以与被调用函数中的形参名一样,也可以不一样。但声明中的函数类型以及各形参类型、形参个数必须要与被调用函数定义中的一致。
- 各“形参名”可以是任意的,可以与被调用函数中的形参名一样,也可以不一样。但声明中的函数类型以及各形参类型、形参个数必须要与被调用函数定义中的一致。
- 2.函数类型 函数名(形参类型1 ,形参类型2 ,…)
- 可以只写形参类型而不写形参的名字,因为编译系统并不检查参数名字,只检查参数类型。
- 意义:便于在编译源程序时对调用函数的合法性进行全面检查。当发现不匹配的函数调用(如函数类型不匹配,参数个数不一致,参数类型不匹配等)时,就会在屏幕上显示出错信息,用户可据此发现并改正函数调用中的错误。
- 可以只写形参类型而不写形参的名字,因为编译系统并不检查参数名字,只检查参数类型。
- 什么情况下需要声明函数?
- 函数定义出现在函数调用之后,需要在主调函数内或主调函数前声明;
- 函数定义是在另一个源文件中;
- 函数定义出现在函数调用之后,需要在主调函数内或主调函数前声明;
- 1.函数类型 函数名(形参类型1 形参名1,形参类型2 形参名2,…);
- 嵌套调用:
- C语言不允许嵌套定义函数,但可以嵌套调用函数。
- 嵌套调用(被调函数做主调函数,再次调用其他函数);
- C语言不允许嵌套定义函数,但可以嵌套调用函数。
- 函数的递归调用:
- 函数调用原理:
- 1.函数调用函数是要压栈(栈空间)的;
- 2.函数调用结束后,要出栈。
- 1.函数调用函数是要压栈(栈空间)的;
- 递归:函数体内直接或间接的调用自身。
- 本质:借助函数自身调用实现的循环结构。
- 实现原理:函数的调用原理实现回推。
- 函数调用原理:
- 实现函数递归的注意事项:
- 函数内部必须要有函数返回的条件;(必须要有出口)
- 函数内部必须要有函数返回的条件;(必须要有出口)
- 对函数返回的判断必须写在函数开始处;(函数开始就要有出口的判断)
- 对函数返回的判断必须写在函数开始处;(函数开始就要有出口的判断)
- 开始递归;
- 开始递归;
- 递归调用时,必须要向出口逼近
- 递归调用时,必须要向出口逼近
- 用递归来求阶乘
- 数组做函数参数:
- 1.数组元素做参数
- 和变量做参数是一样的,是单向的“值传递”。
- 和变量做参数是一样的,是单向的“值传递”。
- 数组名做参数,传递的第一个元素的地址:是“地址传递”,对形参的操作会影响到实参。
- 数组名做参数,传递的第一个元素的地址:是“地址传递”,对形参的操作会影响到实参。
- 被调函数形参为数组时,计算该数组大小为固定值,32位为4字节,64位为8字节。
- 所以在自定义函数形参用数组时,多加一个参数为数组长度。防止自定义函数内对数组的操作产生越界行为。
- 如果是字符数组,存放字符块,不用计算字符数组大小,字符数组中有’\0’结束符。
- 所以在自定义函数形参用数组时,多加一个参数为数组长度。防止自定义函数内对数组的操作产生越界行为。
- 1.数组元素做参数
- 衍生知识点:
- const 关键字 : const 关键字用于修饰变量,用在数组时候表明只能读取数据,不能修改数据;
- const 关键字使用 :
- const int a = 9;
- 用const 修饰的变量,也被称为 只读变量。
- const int a = 9;
- const 关键字 : const 关键字用于修饰变量,用在数组时候表明只能读取数据,不能修改数据;
- 变量的作用域(作用范围)
- 根据变量的作用范围不同,将变量分为局部变量和全局变量
- 1.局部变量(内部变量)
- 函数内定义的变量
- 作用域:仅限于函数内;
- 形式参数也是局部变量:
- 函数内定义的变量
- 全部变量(外部变量)
- 函数外部定义的变量
- 作用域:从变量定义到本文件末。
- 函数外部定义的变量
- 全部变量(外部变量)
- 全局变量:
- 1、设置全局变量增加了函数间数据的联系渠道。
- 2、若在同一源程序文件中外部变量与局部变量同名,则在局部变量的作用域范围内,外部变量被屏蔽,即不起作用。
- 3、建议不在必要时不要使用全局变量,因为:
- ① 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元;
- ② 使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值,程序容易出错。因此,要限制使用全局变量;
- ③ 降低了函数的通用性。因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。但若该外部变量与其它文件的变量同名时,就会出现问题,降低了程序的可靠性和通用性。一般要求把C程序中的函数做成一个封闭体,除了可以通过“实参——形参”的渠道与外界发生联系外,没有其它渠道。
- ① 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元;
- 1、设置全局变量增加了函数间数据的联系渠道。
- 根据变量的作用范围不同,将变量分为局部变量和全局变量
- 变量的存储方式和生存期/生命周期
- 1、变量的生命周期:变量在运行时存在的时间;
- 局部变量:当局部变量定义时产生,函数结束后消亡。
- 全局变量:当全局变量定义时产生,程序结束后消亡。
- 局部变量:当局部变量定义时产生,函数结束后消亡。
- 2、变量的存储方式:变量存放在哪里;
- 变量存储类型:
- 2.1 auto (自动类型)#默认 修饰局部变量,变量存放在栈(段)空间;系统自动回收,用户无法操作;
- 2.2 static(静态类型)
- static 修饰局部变量:变量的作用域不变,生命周期延长;
- static 修饰全局变量:变量的生命周期不变,作用域减少;只限定本文件内使用。
- static 修饰局部变量:变量的作用域不变,生命周期延长;
- 2.3 extern(外部类型)
- 用extern 修饰的变量,表明该变量可能是在其他文件中,或者是在本条语句后定义的。
- extern 修饰全局变量:变量的生命周期不变,作用域扩充
- 用extern 修饰的变量,表明该变量可能是在其他文件中,或者是在本条语句后定义的。
- 2.4 register(寄存器类型)
- register只能修饰局部变量,不更改变量的作用域;
- 一般情况下,变量往往是存储在内存中的,用register修饰的变量存储在CUP的寄存器中。
- 场景:循环变量!
- 一般情况下,变量往往是存储在内存中的,用register修饰的变量存储在CUP的寄存器中。
- register只能修饰局部变量,不更改变量的作用域;
- 变量完整定义格式:
- [存储类型] 数据类型 变量名;
- [存储类型] 数据类型 变量名;
- 2.1 auto (自动类型)#默认 修饰局部变量,变量存放在栈(段)空间;系统自动回收,用户无法操作;
- 变量存储类型:
- 3、变量的存储方式决定了变量的生命周期。


- 1、变量的生命周期:变量在运行时存在的时间;


