函数
难点: 思想
自上而下 逐步拆解
将大问题拆成小问题 小问题拆成更小问题 ---- 更小的问题 往往都对应一个简单独立的功能
函数 ---function
//一个函数就是来完成一个功能的 独立 单一
//getchar/putchar
//scanf/printf
//rand()
//strcpy
//strcmp
//strcat
C语言中实现函数:
函数模型:
输入 ---处理 ---输出
语法:
类型标识符 函数名(形式参数)
{
函数体
//声明部分
//语句部分
}
(1)类型标识符 --- 数据类型 ---反映的是函数带出来的结果的类型
注意:不能是数组类型
(2)函数名 --- 标识符
命名规则和变量名命名规则一致
函数名 一般 反映函数功能
(3)形式参数 --- 函数处理数据模型 (输入-处理-输出)
形式参数 表示函数要处理的数据
数据来源实际给到的参数 (实参)
(4)函数体 --- 完成函数功能的那部分代码
例如:
y = x + 1
eg:
实现一个 功能
两个整数求和
step1:先确定函数名 --- 功能相关
add
sum
step2:从函数模型角度 (输入数据-处理数据-带出结果)
考虑 要处理哪些数据(个数)
哪种类型的数据(数据类型)
eg:
两个整数求和 ---确定形参变量 的个数以及每个变量的类型
形参语法:
格式:
数据类型 形参变量名1, 数据类型 形参变量名2, 数据类型 形参变量名3,......
int a,int b
注意:
每个形参变量,都需要说明类型
step3:处理数据---函数核心功能代码
result = a+b
step4:返回值//返回值类型 相关(我要的结果是什么,我就返回什么)
此时 函数返回值的类型 就是整型
补充:
return (表达式);
eg:
return result;
此例题代码:
int sum(int a,int b)
{
int result;
result = a + b;
return result;
}
使用函数 --- 函数调用
语法:
函数名(实际参数)
例题:找出两个数中的最大值的函数
函数调用方式
1.创造的函数可以作为函数调用的语句
2.可以作为函数调用的表达式
3.可以作为函数调用的实参
注意:
1.实参 和 形参
注意:
1. 每个形参变量,都需要说明类型
2.实参和形参做到 个数相同 类型匹配 一一对应
2.返回值类型
(看的是我创造的这个函数我定义的是什么来性的函数,我的返回值类型就是什么)
如果不写 ,默认是int类型
3.返回值类型 与 返回结果的类型(return 后面返回的那个东西的类型)不一致时,以返回值类型设计为准
4.函数定义的位置
可以放在main函数之前--- 同时起到定义和声明的效果
可以放在main函数之后--- 需要在使用之前,做函数的声明
函数声明
把函数头复制一份 加上 ; //函数调用语句
5.如果 函数不需要 传入数据此时形参 设计为 void (空类型)
返回值 : 如果没有此时也设计为 void
函数的好处
1.降低重复代码的编写,提高编程效率
2.实现了程序的模块化
提高程序可靠性和可维护性
练习:
判断是否是素数?
练习:
写成函数
打印100以内所有的素数
练习:
判断年份是否为闰年?
练习:
获得月份的天数
需要的数据 年份 和 月份
注意:
1. main函数 称为 程序的入口函数
2. 函数可以实现嵌套调用
3. 所有程序的运行,都在内存上运行
栈 --- 数据结构 --- 数据组织方式
C语言程序
运行之后 在内存中布局:
[栈]
[堆]
[全局区/静态区] //存放全局变量 或静态变量
[字符串常量区] //"hello"
[代码区] //代码
栈特点
先进后出 FILO
入栈
出栈
本身是一块内存空间
局部变量 都放在栈上
栈上变量特点 --- 自动申请自动释放
栈 空间 在linux系统上 默认8M 但是可以修改
堆区:
特点:
特别大
手动申请,手动释放
32位系统
4G 操作系统 大约占1G
32位 一般 数据总线宽度
地址总线宽度
0000 0000 0000 0000 0000 0000 0000 0000
1024 = 2^10
1024*1024*1024
1024字节1Kb* 10241MB* 10241GB
函数嵌套调用:
自己调用自己 --- 递归
func1()
{
func1(); //直接递归
}
-------------------------------------------
func2() //间接递归
{
func1();
}
func1()
{
func2();
}
递归:
1.自己调用自己
2.递归是一种特殊的循环
for
while
do-while
效率
从效率上来说for、while、do-while 效率高
有些时候 有些问题的解决,用递归的方式 更容易实现
3.递归解决问题的思路 ---函数调用
倒着来思考的
解决问题n
看看问题n-1能不能解决
还需要知道问题n和问题n-1直接递推关系
实现递归:
1.问题n 和 问题n-1之间递推关系
2.递归结束条件
4. 注意
递归的深度不要太深,太深 可能栈空间不够用了,导致段错误
实现递归代码:
int sum(int n)
{
//if(递归结束条件)
//{
// 返回
//}else
//{
//继续递归下去---sum () 例如:return sum(n-1) + n;
//}
}
练习:
n!
练习:
斐波拉契数列
1 1 2 3 5 8
求斐波拉契数列第n项