复习:
自定义函数:
1、函数声明
告诉编译器函数的格式,方便它检查调用者的参数、返回值
2、隐式声明
当调用函数时如果没有函数声明、定义,编译器会猜测函数的格式,函数的参数按照调用者提供的实参猜测,返回值默认猜测为int类型
C89:完全猜对,没有警告
C99:完全猜对,也会警告
3、函数定义
函数的定义出现在调用之前,可以省略声明
4、函数传参
值传递:
普通变量,函数之间不能共享同名变量(局部)
址传递:
数组,数组长度会丢失,需要额外增加一个参数传递数组的长度,同时该数组能够被两个函数共享(调用者和被调用者)
void func(int arr[],int len)
func(arr,10);
返回值:return语句不是把返回值数据直接传递给调用者,而是把该数据放入他们都能访问的位置,然后调用者去读取。因此函数中没有return语句,调用者也会去读取,只是该位置的数据是一个随机的垃圾数据
进程映像:
程序:存储在磁盘上的可执行文件(二进制、脚本)
进程:在系统中正在运行的程序
进程映像:指的是进程的内存分布情况
text 代码段 二进制指令
只读段 常量
只读的,强制修改会产生段错误
data 数据段
初始化过的全局变量、初始化化过的静态局部变量
bss 静态数据段
未初始化过的全局变量、未初始化化过的静态局部变量
运行前该段会自动清零,默认值是0
heap 堆
由程序员手动管理,缺点:使用麻烦,优点:足够大
stack 栈
局部变量、块变量
由系统管理、会随着函数的调用自动分配内存、函数的结束释放内存
优点:使用方便 缺点:大小有限,超过会段错误
变量的分类:
存储位置、生命周期、使用范围
全局变量: 定义在函数外
data或者bss,取决于是否初始化
从程序运行开始前到执行结束
任何位置
局部变量: 定义在函数内
stack
从函数调用开始到函数执行结束
只能在函数内使用
块变量: 定义在语句块内
stack
从定义语句开始到函数执行结束
只能在语句块内使用
全局、局部、块变量可以同名,同名的局部屏蔽全局,同名的块屏蔽局部、全局变量
全局变量首字母大写
类型限定符:
auto
用于定义自动申请、释放内存的变量,不加就代表加
不能在全局变量前使用,也不能与static同时使用
extern
用于声明外部的全局变量
当a.c中定义一个全局变量,b.c中如果想要使用就需要用extern声明一下
如果没有,只能通过编译,不能通过链接
不能对声明语句赋值
static
改变存储位置
局部变量、块变量,由stack改为data或bss
延长生命周期
局部变量、块变量,函数结束时不会被自动销毁,它们的初始化语句只有第一次时生效
限制使用范围
全局变量、函数,限制为本文件内使用
const
"保护"变量不被显式地修改
初始化过的全局变量、静态局部变量被const修饰后存储位置会变成text,变成了真正的常量
volatile
如果变量没有显示地被修改,再次使用该变量时会继续使用上一次读取的结果,而不会读取内存(取值优化)
如果有些变量可能被隐式地修改,想要随时读取准确的数值,就需要使用volatile修饰一下
在硬件、多线程编程使用
register
申请把变量的存储位置由内存改为寄存器,提高变量的读写速度,从而提高程序运行速度
由于寄存器数量有限,不是每次申请都能成功
注意:这种变量不能取地址
typedef
类型重定义,如果在定义变量前加typedef,变量名就等同于类型
常见 size_t time_t uint8_t... 都是使用typedef重新定义出来的
typedef int INT
注意:不是替换
#define
五子棋:
需要的数据:(全局)
1、定义棋盘二维数组 15*15 空位置 '*'
2、定义棋子角色变量 白棋 '#' 黑棋 '$'
3、定义变量用于记录下棋的位置
业务逻辑:(实现成一个个函数)
是否需要初始化
for(;;)
{
1、清理屏幕、打印棋盘
2、落子
输入坐标,坐标合法、该位置不能有棋子,否则继续落子
3、判断是否五子连珠
4、交换角色
}