函数
是一段具有某项功能的代码,是C语言中管理代码的最小单位,是一个代码模块,命名空间、栈空间是独立的。
把代码封装成一个个的函数,可以方便管理和调用代码
函数的分类
标准库函数
C语言标准委员会为C语言以函数形式提供一些基础的功能,被封装在libc.so库,默认添加的,所以使用时需要包含头文件,以函数名(参数) 来调用函数
int isalnum(int c);
int isalpha(int c);
int isdigit(int c);
int islower(int c);
int isupper(int c);
int isxdigit(int c);
int toupper(int c);
int tolower(int c);
int abs(int j);
以下函数被封装在libm.so 数学库中,使用时需要在编译时加参数-lm
double sqrt(double x);
double pow(double x, double y);
double ceil(double x);
double floor(double x);
double fabs(double x);
time_t time(time_t *t);
功能:返回自1970-1-1 0:0:0 到运行时过了多少秒
int system(const char *command);
功能:调用系统命令 system("clear");
int rand(void);
功能:返回一个随机数
void srand(unsigned int seed);
功能:种随机种子,设置取随机数的位置
系统函数
系统函数不是函数,只是操作系统以函数接口的形式提供的一些功能
内存管理、信号处理、文件IO、文件管理、进程管理、进程通信、线程管理、线程同步、网络通信
第三方库函数
由第三方提供的收费、开源的库函数
github
MD5
XML
JSON
自定义函数
为了更方便地管理代码、减少冗余把代码封装成函数
注意:一个函数尽量控制在50行左右,一个函数一个功能
函数声明
函数声明目的是为了告诉其他代码该函数的调用格式,方便编译器检查调用时的格式是否正确
返回值类型 函数名(类型1 变量名1,类型2 变量名2…);
1、C语言中函数名一般全部小写,用下划线分隔
2、如果不需要参数建议写void,不要空着
3、如果不需要返回值写void
4、如果在调用前有函数的定义,那么函数声明可以省略
隐式声明
当调用函数时没有函数声明或定义,编译器会猜测函数的格式,参数列表会根据调用时的提供数据来猜测,返回值猜测为int类型,要避免隐式声明
如何避免:在调用前,提供函数的声明或定义
函数定义
返回值类型 函数名(类型1 变量名1,类型2 变量名2...)
{
函数体; // 尽量不要超过50行
return val;
}
注意:return语句的作用:1、返回值给调用者 2、结束函数的执行
注意:如果不需要返回值写void,不需要参数也写void,防止产生歧义
函数调用
函数名(实参);
返回值会放在调用的位置,可以用变量记录下来,也可以直接显示,如果不记录就会丢失
函数传参
1、实参与形参之间是以赋值的形式传递数据的(单向值传递)
2、在函数内定义的参数,只属于它所在的函数,出了该函数就不能在使用了
3、return语句其实是把数据放置到一个公共区域(函数和调用者共用),如果不写return语句,调用者从该区域中获取的是一个随机的垃圾数据
4、当数组作为函数的参数时,长度会丢失,数组会脱变成指针,需要额外多加长度的参数来把长度传递过去
5、数组的传递是"址传递",函数和函数的调用者可以共享数组
6.不要返回局部变量的地址,原因是随着函数的执行结束,局部变量会自动被释放,因此返回的是野指针。
设计函数的准则
1、一个函数最好只解决一个问题,从而可以降低出错率
2、最好不要过分依赖其他函数,降低耦合度
3、数据由调用者提供,结果返回给调用者,以此提高函数的通用性
4、对于调用者提供的非法参数,可以通过返回值、注释等方式来告诉调用者数据非法,以此提高函数的健壮性
5、一个函数最多不要超过50行
递归
函数自己调用自己的行为叫递归,它的本质是一种带状态的循环。
使用递归可以实现分治算法、解决树结构的问题。
递归函数每调用一次,就会对自身进行拷贝(分配栈内存),这些内存可以用于传递状态、参数,但也会耗费很多内容空间和时间。
能使用循环的问题就尽量使用循环解决,不能使用循环的再考虑使用递归。
例如:汉诺塔(记录状态) 全排列(树型结构问题)只能使用递归解决。