函数
思想:
举例: ATM机
//把抽象的东西具体化 //----把一个大问题逐步拆成更小的问题
功能: 存钱 取钱 查询 转账 信息修改 退出
这里面的每个具体问题都可以用一个函数来实现。
使用函数来设计程序更符合C语言结构化设计的思想,把大问题拆成小问题,能减少重复劳动,提高编程效率。
函数的定义
函数的定义:
类型标识符 函数名()
{
声明部分
语句部分
}
----------------------------------------------- ------------------------------------------------------------------ ---------- 返回值的类型标识符 函数名(形式参数) //函数头 head
{
函数体 //body
}
返回值的类型标识符 //用来说明 该函数(fumction)带出的数据的类型
函数名 //其名字的方式和变量名的方式一致
//数字字母下划线 不能是数字开头
形式参数 //是用来接收实际参数的变量
函数体 //函数体就是实现具体功能的代码
注意的是在设计函数名的时候要设置成直接反应函数的功能。
数据 -> 函数-> 结果
//考虑这个函数需要用到哪些数据 -----形式参数
形式参数:
类型名 形式参数变量名1,类型名 形式参数类型名2 ......
注意:
1、每一个形式参数都有自己的类型名
int a,int b //形式参数的定义
不能写成int a,b;
//实现函数体-函数具体功能的代码
int result = a + b;
//要带出什么样的结果? ----函数返回值的设计
带出计算的结果
int sum(int a, int b)
{
int result = a + b;
return result;
}
!!如果要带出结果:
return 语句; //表示,从函数中返回(就是函数结束啦)
return 表达式; // return 可以把表达式的结果返回给调用函数的程序
函数调用:
语法:
函数名(实际参数);
eg:
int ret;
ret = sum(a,b);
//在调用的时候得接收函数的返回值
注意:
1、返回值类型说明符 可以不写 ---此时默认是int类型
2、返回的结果,与返回值类型说明符之间不一致时,一返回值类型说明符的类型为主
3、形式参数的格式!!
写的时候
用的时候
形式参与与实际参数之间 个数要相同
类型要匹配
一一对应的 ` //第一个实参 就给到第一个形参
4、标识符使用的时候,一定是先定义后使用
可以直接把函数头放在使用的前面 //也就是函数(原型)声明 。。。函数头加 ;
----------
函数可以定义在main函数之前 也可以定义在main函数之后
如果定义在main函数之后,在使用前,必须要有函数声明
如果函数没有返回值,,此时返回值类型说明符
qq))如果函数不需要参数,则形参可以写成void
??有的函数定义不能卸载main函数里面
哪些??
注意:
函数不能嵌套定义
函数可以嵌套调用
特殊的嵌套调用:
函数自己调用自己
间接递归和直接递归? //函数里面调用自己啦
递归从本质上说其实是个循环,这个循环和while do while for 都有区别
递归不能构成死循环!!!!!!!
用递归!:
循环:
递归的过程实际上是函数的调用,而函数调用需要使用栈空间(内存空间)。
注意:所有的执行程序都是在!内存!中运行的
CPU一条一条的执行机器指令,来运行程序
CPU中有 --> pc寄存器---pc-->指程序计数器
存放着下一条要执行的指令。
软件安装在硬盘上;
输入
存储器(内存) + 控制器
CPU(寄存器) //运算器+控制器 = CPU
输出
!!!! 栈 ---是一种数据结构 栈在函数控制中有很大的作用
1、FILO 先进后出
2、内存上的一块空间 大小有限,
可以存放函数调用数据
栈 越界会发生段错误
3、-----压栈 向栈中保存数据遵循FILO原则
4、局部变量(自动变量)
自动申请,自动释放
堆:
1、空间很大
2、手动申请,手动释放
字符串常量区:
“hello” //字符串常量 这块空间只读 不能被修改
全局区(静态区):
主要放全局变量,
代码区:
存放代码的
程序 = 数据 + 代码
---------------------------------------------
汉诺塔??Hanoi塔问题 -----> 递归的思路
----------------------------------------------------
函数与数组:-----数组作为函数参数
1、函数传参
实参 赋值给 形参
2、数组传参
//想把整个数组的数据传给被调函数
形式上:
void printArray(int a[],int len) //形参1 表示要传的是数组 形参二 表示要传的是数组的长度
本质上:
void printArray(int *a,int len) //指针变量(接收地址这种数据)
调用时:
printArray(&a[4],5); //a ---数组名 ---数组首元素的地址
注意:如果函数传的是数组
通过数组下标的访问方式,可以实现被调函数,修改主调函数中的数据;
---------------------------------------------------
函数与字符型数组
注意:一维字符型数组作为函数的参数:
和一位整型数组作为函数参数方式是一样的
但不需要传数组长度 ,因为字符串有自己的结束标志。
对二维数组 sizeof(a)/sizeof(a[0]) 求出的结果是 这个二维数组有几行
函数引入二维数组的时候
eg:
void printArray(int a[][4]) //注意 这个列数不能省!!!
二维数组做函数参数
形参:
1、 要写一个二维数组的形式 。
2、 需要传递行数。
实参:
1、 传数组名
2、 传二维数组行数
一维字符型数组传参的时候不用传长度
总结:
函数的思想
函数语法
注意:
函数传参 --- 传递过程 ---值传递
函数与数组 ---数组作为函数参数
{
一维整型数组 形参(数组形式,长度) 实参(数组名,数组长度)
一维字符数组 形参(数组形式) 实参(数组名)
二维整型和二维字符型 形参(数组形式,行数) 实参(数组名,行数)
}
8.8 8.9
标识符的作用域与可见性问题
标识符
名字
int a; //
int max0fArray(int a[], int len) //
作用域:( scope )
标识符作用的范围 ---起作用的范围
空间上:
局部作用域
--在花括号范围之内
全局作用域
--不在任何一个花括号范围之内
可见性:
程序运行到某句代码时,哪些标识符是可见的。
标识符可见性的规则:
1 先定义后使用
2 同一作用域不能有同名标识符 //重复定义啦
3 在不同的作用域,同名标识符,相互之间没有影响
4 如果是不同作用域
但作用域之间存在‘嵌套关系’
则,
内层的作用域的同名标识符,会屏蔽外层的作用域的同名标识符(就近原则)。
空间角度划分开:全局变量和局部变量
//时间角度:
auto
static 如果在局部变量的定义前面,此时将局部变量变为了静态变量
存储的空间发生变化了,到了静态区/全局区
生命周期变成了整个程序的生命周期
注意:
static修饰的变量 不能用变量进行初始化哦
auto int a; //自动变量 ----空间开在栈上----生命周期:从程序指定到定义出开始存在,到作用域结束结束。
int a = 10; //
c语言加载到内存中,会安排到五个区:
动态空间: 栈 数据区 //局部变量 自动申请 自动释放
堆
字符串常量区
全局区(静态区) //这块空间代码编译好就一直存在
//生命周期,从程序开始到程序结束
-----------------------------------------