7、函数
目录
一、函数的作用
1、封装功能代码 --解决重复使用的问题 --一次定义,多次调用
2、减少主函数的代码内容,方便排错。
3、一个 C 程序可由一个主函数和子函数构成。语句是构成程序的最基本单位,函数也是由语句构成的
4、函数从用户使用的角度可以分为:标准函数和用户自定义函数。
标准函数:即库函数。由系统提供的设计好的函数,用户可以直接调用,例如: printf()—scanf()—fabs()—sqrt()—gets()—getchar()等等都是库函数。
用户自定义函数:用户自己根据需要定义的函数。
5、函数从形式上又可以分为:无参函数和有参函数。
6、实现一个函数主要分为 3 个步骤:函数的定义、函数的声明、函数的调用
二、主函数main
1、void main(){};
2、int main(){};
3、void main(int argc,char *argv[],char *env[]){};
(1) argc -- 传入的参数个数
(2)argv -- 传入的参数内容 --字符串
(3)env --运行程序所需的环境参数 -- 默认环境运行
4、int main(int argc,char *argv[],cagr *env[]){};
三、函数的定义
1、返回值类型 函数名(形参){函数体};
(1)返回值类型 --可以是所有的数据类型 包括void(无类型)
(2)函数名 -- 同标识符
-- 组成 :数字、字母、下划线
--要求:
不能是数字开头
不能是关键字
区分大小写
有意义 --望文生义
双驼峰命名 --Get_User_Name,不强制要求,但最好养成习惯
(3)形参 --形式参数 --没有具体的值 --在函数功能定义时,起占位作用
--作用:使函数更具有灵活性。 -- 形参也是有内存空间的
(4)函数体 -- 功能的实现代码
2、函数定义形式 -- 尽量避免在函数中进行输入输出操作,函数重点在于功能实现。
(1)无参无返回 --默认使用
(2)无参有返回
-- 函数定义时,具有返回值类型,那么在函数体中必须使用return返回该类型的数据
(3)有参无返回
(4)有参有返回
四、函数的声明
1、声明的位置:调用者的上面。
2、声明内容:返回值类型 函数名(形参); -- 这也是函数类型的表现形式
-- 声明时与形参的数量、类型、顺序有关,与参数名无关。-- 只要形参的有这些变化,函数就不同。
五、函数的调用
1、函数的调用方式
(1)主函数 调用 子函数
(2)子函数 调用 子函数
(3)自己 调用 自己 --退出的条件 --递归
2、函数的调用形式
(1)无参无返回 --函数名();
(2)无参有返回 --函数名(实参); --函数具有形参,那么在调用时必须提供一个实参。
(3)有参无返回 -- 返回值类型 变量 = 函数名();
(4)有参有返回 -- 返回值类型 变量 = 函数名(实参);
3、函数的执行顺序 --中断机制
六、形参与实参
1、形参
--形式参数 --没有具体值 --在函数定义时使用 --变量的定义
2、实参
--实际参数 --有具体值 --在函数调用时使用 --变量的赋值
注:int a = n;n只可能是实参,因为实参才能赋值,只能把实参赋给形参
3、实参的数量、顺序、类型要与形参保持一致。
4、形参和实参的变量名可以一致,因为形参和实参分别占用不同的内存空间,所处的的位置不同。
七、函数应用
1、形参相关的应用
(1)基本数据类型作为形参
(2)数组作为形参 -- 同类型三个或三个以上的参数
-- 数组作为参数进行传递,实际传递的是数组的首地址
1)数值数组 -- 需要把长度一起传递给函数 --多加一个参数
2)字符数组 -- 字符串常用函数strlen计算长度
3)指针作为函数的参数
-- 值传递
-- 地址传递
2、返回值类型相关应用
(1)基本数据类型作为返回值
(2)数组作为返回值
-- 数组作为函数的返回值类型 -- 实际返回的是数组的首地址 --因此直接返回指针类型
-- 在函数中定义数组或者指针时,需要把数组和指针定义为全局变量,否则函数执行完,空间会被销毁 -- 使用static修饰,把局部变量升级为全局变量
-- 字符串常用函数
字符串复制:char *strcpy(char *dest,char *src); --复制函数返回的是目的串的首地址
字符串拼接:char *strcat(cahr *dest,char *src);
(3)指针作为函数的返回值 -- 库函数:malloc --手动开辟空间,返回任意类型的首地址 --Void *malloc(size_t size);
注:malloc函数返回值是任意类型的指针,要强转成需要的数据类型的指针。如(int *)malloc(sizeof(int));
3、指针函数 --函数指针 --函数指针数组
(1)指针函数 -- 是函数 --返回值是指针
(2)函数指针 --指针 --函数类型的指针
-- 定义: 返回值类型(*标识符)(形参)
--函数指针代替函数名执行函数
(3)函数指针数组 -- 数组 --函数指针类型的数组 --数组元素是函数地址
--定义:返回值类型(*标识符[长度])(形参)
注:返回值是int型,但是写的是return 'a'; 也是可以的,因为可以强转,但是最好写的是对应的。
函数返回值类型是引用或指针的时候,要注意不要返回一个临时的局部变量。因为临时的局部变量在函数{}之后内存空间就会自动释放。
在函数调用的时候,系统会为函数的形参分配内存空间,并将实参的值赋给形参,而且会开辟一个存放返回值的公用内存空间。
八、全局变量和局部变量
注:全局变量具有初始值,例如整数的初始值是0,指针的初始值是NULL
1、全局变量与局部变量是否可以重名?
--可以重名,重名后使用局部变量 --就近原则
2、如何提高局部变量的生命周期?
--关键字:static --可以提高局部变量的生命周期,但不提高其作用域。意思是static修饰的变量在函数执行完后不会立马销毁,还会保存在全局变量里,下次再此执行函数时的变量时,从全局变量(静态变量)中找到,从当前值开始执行,不会再执行static修饰变量那句开始执行。
九、关键字static和extern
1、extern
-- 修饰函数和全局变量的声明,表示该函数或全局变量时引用外部资源的内容。
--模块化开发 --分文件编写代码
--例如在a.c中想用b.c中的函数,那么在a.c中main函数上声明函数时需要在前面加上extern。
--extern void test(void);
(1)分文件 --多个文件属于一个程序,一个程序有且仅有一个主函数
(2)多文件中出现重复的函数,使用static修饰,将其中一个函数私有化,或者改名字。--static将函数私有化后,别的程序中无法调用。
(3)extern修饰声明函数时可以省略不写,但是修饰全局变量时,尽量不要忽略。
-- 就是在执行gcc a.c b.c时,如果在a.c中声明b.c的函数,extern可以省略不写,程序会自动去b.c中找。
(4)多文件同时编译
--gcc a.c b.c ......
--gcc *.c
2、static
(1)static修饰局部变量时,可提高其生命周期,不提高其作用域。
-- static是把变量放在全局变量,再次遍历的时候不用再次赋值,就按原先的值的基础上运行。也就是说static int a =10;只会执行一次。satic在函数中定义,只能在函数中使用。
(2)修饰全局变量或函数,表示其内容为私有化,不外借
十、c语言的内存分区
1、栈区 --自动开辟,自动释放
2、堆区 --手动开辟,手动释放
3、常量区
4、全局区(静态区)
5、代码区