函数
函数的设计尽量高内聚低耦合(自己设计自己的)尽量不关系别人
尽量少使用全局变量:全局变量可以改变的地方比较多,不安全
1. 分类
库函数
- IO函数:input/output/printf/scanf/getchar/putchar/
- 字符串操作函数:strlen/strcmp/strcpy/stract
- 字符操作函数:tolower/toupper
- 内存操作函数:memcpy/memset/memmove/memcmp
- 时间/日期函数:time
- 数学函数:sqrt/abs/fabs/pow
- 其他库函数:根据网站Reference - C++ Reference (cplusplus.com)学习函数
getchar/putchar:读取/输出字符
返回类型是int整型,因为返回的是字母,字母对应ascii码值为整型数字
读取失败时候会返回EOF —— end of file = -1
gets直接读一行不管有无空格
int main()
{
int a = getchar();
}
//像scanf/getchar的函数 输入一段字符再回车,下一个此类函数会直接拿走剩下在缓冲区的'\n'
//scanf碰到空格就不会再读了相当于读了个'\0'
int main()
{
char password[20] = {0};
printf("请输入密码:>");
scanf("%s", password);
//把缓冲区中的内容
int tmp = 0;//把空格之后的字符串存起来
while ((tmp = getchar()) != '\n')
{
;//这里指什么都不做
}
printf("请确认密码(Y/N):>");
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
自定义函数
无返回值/空函数 (以交换值函数为例操作)
void swap(int *x,int *y)//注意这里定义形参的类型是指针
{
int z = 0;
z = *x;
*x = *y;
*y = z;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
swap(&a, &b);//注意这里是取的是a和b的地址
//传参方式:传址调用
return 0;
}
有返回值(例子相同作对比)
int swap(int x,int y)//注意这里定义形参的类型是整型
{
int z = 0;
z = x;
x = y;
y = z;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
swap(a, b);//注意这里是取的是a和b的值
//传参方式:传参调用
return 0;
}
2. 函数的调用
传参调用:函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传址调用:可以使函数和函数外边的变量建立起联系,函数内部可以直接操作函数外部的变量。
3. 函数的嵌套使用
函数可以嵌套调用,但是不能嵌套定义。
4. 函数的链式访问
#include <stdio.h>
#include <string.h>
int main()
{
printf("%d\n,strlen("abc"));//链式访问
printf("%d", printf("%d", printf("%d", 43)));
//printf的返回值是打印字符个数,所以输出结果为4321
return 0;
}
5. 函数的声明
先声明后使用
int function1()
{
}
int function2(int a);
int main()
{
function1();//函数在前面 就不用声明
int function2(int a);//只要在使用之前声明就行
function2();//函数在后面需要调用
}
int function2(int a)
{
}
在工程中函数的声明使用
- 新建.c源文件,存放定义的函数
- 新建.h头文件,存放函数的使用声明
- 在需要使用该函数的文件中前头加上 #include “xx.h” 即可使用该函数
分块写代码好处:
- 多人协作(比如写一个计算机中,分 总模块 加法 减法 乘法 除法 分别分给不同的人去写)
- 封装和隐藏(购买外包代码)
关于如何包装:将定义函数的.c文件和声明该函数的.h文件复制到新的项目中,将项目属性中,常规-配置类型-改成静态库.lib,然后运行。得到.lib文件,将.lib文件和.h文件放到所要应用的工程里,使用时候前加上
#include “xxx.h” 头文件 + #pragma comment(lib,“xxx.lib”) //导入静态库
ps: 可以在头文件中包含以下代码,无论在源文件声明多少次都只会拷贝一份
//关于一个test.h
#pragma once
extern xx;
//或者是
#ifndef __TEST_H__ //判断有没有声明
#define __TEST_H__
int num(int x);//函数的声明
#endif
//二者等价
6. 函数递归
-
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
-
每次递归调用之后越来越接近这个限制条件。
Stack overflow 出现该错误 表示栈溢出 意味着限制条件没有限制住
7. 函数的递归和迭代
- 在使用 fb(n)=fb(n-1) +fb(n-2)这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时
什么时候用递归:
1.当解决一个问题递归和非递归都可以使用,且没有明显问题。那就可以使用递归。
2.当解决一个问题递归写起来很简答,非递归比较复杂,且递归没有明显问题,那就用递归。.
3.如果说用递归解决问题,写起来简单,但是有明显问题,那就不能使用递归,得写出非递归的方式来解决。