“C语言部分-Day05”
一、函数
函数的构成
其中返回值类型不能为数组
1.1 值传递和引用传递
1.1.1 值传递
值传递分为:
值传递案例一:交换案例
当我们按以下方法写swap函数,发现swap函数并没有交换成功
因为swap函数中的int a和int b
实际上是复制了一份,放在栈里(临时存储在内存中),用完即被释放,称为值传递,如何解决这个问题?第一种方法是使用指针传递,如下代码:
值传递案例二:一维数组作为参数
值传递案例二:二维数组作为参数
1.1.2 引用传递
解决1.1.1值传递交换案例不成功的第二种方法,就是使用引用传递
注意事项:
在VS中,以上main.c源码文件使用C编译器报错:存在正文时不允许未命名的原型参数
解决方法:改成main.cpp
1.2 程序的终止
程序的开始和结束:
- 操作系统调用main函数 —-> 程序的开始
- main函数将状态码返回给操作系统 —–> 程序的终止
如果不想在main函数终止,如何提前终止呢?
二、局部变量和全局变量
2.1 定义局部和全局变量
分为全局和局部(外部)变量:
- 局部变量:定义在函数里面的变量(默认在自动存储期限,可以用static指定为静态)
- 全局变量:定义在函数外面的变量
2.2 存储期限(※※※)
存储期限分为:
- 自动存储期限:存在栈里面的数据,变量的生命周期随栈帧的入栈开始,出栈而结束
- 静态存储期限:拥有永久的存储时间,在程序整个执行期间都存在
自动存储单元的案例(该案例仅能在部分Linux中编译执行,实测效果不同):
如果改成:
再改成静态存储:
三、递归(※※※※)
3.1 斐波那契数列(TODO 补充递归优化版本)
斐波那契(Fibnaci)数列,从第三个数开始,后面的数值为前2个数值之和:
0,1,1,2,3,5,8,13……
递归实现:
不过递归这样写,算法效率非常低,存在大量重复运算符(如图,同色的为重复运算),时间复杂度是O(2^n)。
改良的方法是使用循环实现,时间复杂度是O(n),效率比递归高很多
3.2 约瑟夫环(TODO)
给定人数、起点、方向、要跳过的数字
四、指针(※※※※)
4.1 指针的基础
几个基础知识:
- 字节:计算机最小的寻址单位
- 变量的地址:变量的第一个字节的地址
- 指针:指针就是地址
- 指针变量:存放地址的变量,有时候吧指针变量称为指针
4.1.1 通过指针访问对象
如何通过指针访问到其指向的对象:
注意事项:
int *p, q; // p是指针int*类型,q是int类型
int *p, *q; // p、q都是int*类型
4.1.2 野指针的问题
什么是野指针?
注意事项:
对野指针进行解引用行为,将导致编译器报错:如,读取访问权限异常
4.1.3 指针变量的赋值
4.1.4 指针作为参数(※)
指针作为参数的好处:
练习:找出数组中的最大值和最小值
4.2 指针和数组
4.2.1 指针运算
指针运算包含:
- 指针加上一个整数
- 指针减去一个整数
- 两个指针相减(指向同一数组里的元素)
指针运算以元素大小为单位,而不是以字节位单位。案例如下:
指针变量p1减p2的意义为:
- 如果是正值 , 则表示在内存中p1比p2靠后
- 如果是负值 , 则表示 在内存中 p1比p2靠前
- 结果的数字表示 , 两个地址在内存中间隔多少个指针类型的字节倍数
4.2.2 使用指针遍历数组
for循环方式
while循环方式
4.2.3 *和++的组合
四中组合的含义:
**p++ 或 (p++) :
**(*p)++**:
***++p或*(++p)** :
**++*p或++(p)* :
*和–也有类似的组合
4.2.4 指针作为数组名使用
案例如下: