函数(又名子程序),是一个大型程序中的某部分代码,由一个或者多个语句块组成。它负责完成某项特定任务,而且相较于其它代码,具备相对独立性。
函数分类:库函数(官方封装,可直接调用)、自定义函数;
注意:C语言只规定了标准和库函数的约定,具体的实现是编译器自己实现的。因此,不同的编译器底层不一定相同,但调用的方法和返回之后是一样的。
一、库函数
库函数学习地址:www.cplusplus.com 【新版不好用,用老版本,右上角“legacy version”】;
简单总结,C语言常用的库函数都有:
- IO函数 —— 输入/输出函数:scanf、getchar、putchar、printf...
- 字符串操作函数 —— strlen、strcmp...
- 字符操作函数 —— islower()判断一个字符是否是小写、isupper()判断一个字符是否是大写...
- 内存操作函数 —— void* memset(void* ptr, int value, size_t num)将ptr指向的内存的前num个字节的值设为value、memcmp...
- 时间/日期函数 —— time...
- 数学函数 —— sqrt
- 其他库函数
二、自定义函数
和库函数唯一的区别就是需要自己写。
函数返回类型 函数名(函数参数)
{
函数体;
}
注意:1)自己编写函数的时候要注意形参和实参的问题,形参只是实参的临时拷贝,修改形参对实参没有影响,想要修改实参请用指针;2)写函数的时候功能尽量单一,避免不需要的功能;
三、函数的声明与定义
函数的定义如果写在函数调用之后,或者处在另一个源文件中,编译器就无法识别调用函数,此时在调用之前先声明一下函数就可以了。
// 函数声明
函数返回类型 函数名(参数类型。参数类型...);
注意:1)函数声明一般放在头文件中.h,源文件引用一下头文件就行;—— #include “xx.h”
拓展:1)项目加密:项目右击—>属性—>常规—>配置类型—>从(应用程序.exe)改为(静态库.lib)。从.lib文件打开,源代码显示为乱码,实现源代码保护功能。别人想使用的时候,只需要引用头文件,导入静态库就可(#pragma comment(lib, "xx.lib"))
四、函数递归
函数递归就是函数自己调用自己。写函数递归的时候,最重要的是防止死递归,防止栈溢出结束。递归的好处在于代码量少,但多次调用函数,计算机负担反而更重,最好就不要用。
// print函数按照位打印输入参数
void print(unsigned int n)
{
if (n > 9) // 限制条件,使递归有结束的条件
print(n/10); // 递归修改,使递归朝着结束改变
printf("%d ", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
print(num);
return 0;
}
五、函数栈帧的创建和销毁
函数栈帧的创建和销毁,在不同编译器和不同版本可能略有差异,但大体逻辑是一致的;
回顾:寄存器>缓存>内存>硬盘>网盘(越往上越贵,一般空间会更小)【C语言学习笔记(一)】
寄存器:ebp、esp这两个寄存器存放的是地址,是用来维护函数栈帧的;
VS中查看堆栈途径:调式—>窗口—>调用堆栈
main()函数也是被其它函数调用的,如VS2013中,【main()<—__tmainCRTStartup<—mainCRTStartup】。