第十二章 - DDL-Killer/The-road-of-Linxu-Group2024 GitHub Wiki
存储类别
- C语言提供了不同的模型或存储类别在内存中储存数据
- 数据储存在内存中,从硬件方面来看,被储存的每个值都占用一定的物理内存,C语言把这一块内存称为对象
- 对象可以储存一个或多个值
- 标识符是一个名称,可以指定特定对象的内容
- 标识符既是软件指定硬件内存中的对象的方式,还提供了储存在对象中的值
作用域
- 作用域描述程序中可以访问标识符的区域
- C变量的作用域可以是块作用域、函数作用域、函数原型作用域或文件作用域
- 块是用一对花括号括起来的代码区域
- 变量的类型定义在函数的外面,具有文件作用域
- 文件作用域变量也称做全局变量
链接
- C变量有三种链接属性:外部链接、内部链接和无链接
- 具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量
- 具有文件作用域的变量可以是外部链接或内部链接
- 外部链接变量可以在多文件程序中使用,内部链接变量只能在一个翻译单元中使用
存储期
- C语言有4种存储期:静态、线程、自动、动态分配
- 如果对象具有静态存储期,那么它在程序的执行期间一直存在,文件作用域变量具有静态存储器
- 以
static
声明的文件作用域变量具有内部链接
- 线程存储期用于并发程序设计,程序执行可被分为多个线程。具有线程存储期的对象,从被声明时到线程结束一直存在
- 块作用域的变量通常都具有自动存储期,当程序进入定义这些变量的块时,为这些变量分配内存,当退出这个块时,释放刚才为变量分配的内存
自动变量
- 属于自动存储类别的变量具有自动存储期、块作用域且无链接
- 默认情况下,声明在块或函数头中的任何变量都属于自动属于存储类别
- auto是存储类型说明符
- 块作用域和无链接意味着只有在变量定义所在的块中才能通过变量名访问该变量
- 变量具有自动储存期意味着,程序在进入该变量声明所在的块时变量存在,程序在退出该块中消失
- 没有花括号的块
- 作为if或循环的一部分,即使不用花括号,也是一个块,整个循环是它所在块的子块,循环体是整个循环块的子块
- 自动变量的初始化
寄存器变量
- 变量通常储存在计算机内存中,通常储存在最快的可用内存中
块作用域的静态变量
- 静态变量的意思是变量在内存中原地不动,并不是说它的值不变
- 具有文件作用域的变量自动具有静态存储期
- 局部静态变量是表述具有块作用域的静态变量的另一个术语
外部链接的静态变量
- 外部链接的静态变量具有文件作用域、外部链接和静态存储期,属于该类型的变量称为外部变量
- 可以使用关键字extern再次声明
- 外部变量具有静态存储期
- 初始化外部变量
- 使用外部变量
- 外部名称
- 定义与声明
- 第一次声明被称为定义式声明,第二次声明被称为引用式声明
- 关键字extern表明该声明不是定义
内部链接的静态变量
- 在所有函数外部用存储类型说明符
static
定义的变量具有这种存储类型
多文件
- 如果外部变量定义在一个文件中,那么其他文件在使用该变量前必须先声明它(用extern关键字)
存储类别说明符
- auto说明符表明变量是自动存储期,只能用于块作用域的变量声明中
- register说明符也只用于块作用域的变量,它把变量归为寄存器存储类别,请求最快速度访问该变量,同时保护该变量地址不被获取
- static创建对象具有静态存储期,载入程序时创建对象,当程序结束时对象消失。
- 用于文件作用域声明,作用域受限于该文件;
- 作用于块作用域声明,作用域受限于该块,程序在运行对象就存在并保留值,只有执行块内代码时,才能通过标识符访问;
- 块作用域的静态变量无链接,文件作用域的静态变量具有内部链接
- extern说明符表明声明的变量定义在别处,如果包含extern的声明具有文件作用域,则引用的变量必须具有外部链接
存储类别和函数
- 外部函数可以被其他文件的函数访问
- 静态函数只能用于其定义所在的文件
存储类别的选择
- const数据在初始化之后就不会被修改
- 随意使用外部存储类别的变量导致的后果远远超过所带来的便利
随机数函数和静态变量
掷骰子
- 随机数求模6
- 结果加一,新值在1~6之间
- 把第一步中的数字6换成骰子面数
分配内存:malloc()和free()
- 指向void的指针,坚持使用强制类型转换
- malloc()接受所需内存字节数,内存是匿名的,返回值时动态分配内存块的首字节地址
- 创建数组的方法:
- 声明数组,用常量表达式表示数组的维度,用数组名访问数组的元素
- 声明变长数组,用变量表达式表示数组的维度,用数组名访问数组的元素
- 声明一个指针,调用malloc(),将返回值赋给指针,使用指针访问数组的元素
free()的重要性
- 静态内存的数量在编译时是固定的,在程序运行期间也不会改变
- 自动变量使用的内存数量在程序执行期间自动增加或减少
- 动态分配内存数量只会增加,除非使用free()释放
- 耗尽所有内存问题称为内存泄漏
calloc()函数
- 第一个参数是存储单元数量,第二个参数是存储单元大小
- 把所有块位置都设为0
动态分配和变长数组
存储类别和动态内存分配
- 具有外部链接、内部链接和无链接的静态变量:开始创建,结束销毁
- 自动变量:栈
- 动态分配:堆,比栈内存慢
ANSI C类型限定符
const类型限定符
- 在指针和形参中使用const
- 区分限定指针本身还是限定指针指向的值
- 在类型的左侧:指向一个类型的指针,指向的类型不能改变
- 在类型和*的右侧:指向的地址不能变,但是地址的值可以变
- 在类型右侧,*的左侧:指向一个类型的指针,指向的类型不能改变
- 对全局数据使用const
volatile类型限定符
- 代理可以改变该变量的值,通常被用于硬件地址以及在其他程序或同时运行的线程中共享数据
- 使用二次同一变量但是未改变数值时,编译器会把值临时存储在寄存器,在使用时,从寄存器读取x的值,称为高速缓存
restrict类型限定符
- 允许编译器优化某一部分代码来支持更好的计算,只能用于指针,表明该指针是访问数据对象的唯一且初始的方式
小结
- 自动:在块中不带存储类别说明符或带auto存储类别说明符声明的变量属于自动存储类别,具有自动存储期、块作用域、无链接
- 寄存器:在块中带register存储类别说明符声明的变量属于寄存器类别,具有自动存储期、块作用域、无链接,且无法获取地址
- 静态无链接:在块中用static类型,具有静态存储期、块作用域、无链接,未初始化则字节为0
- 静态外部链接:在所有函数外部没有使用static,静态存储期、文件作用域、外部链接,未显示初始化则字节为0
- 静态内部链接:在所有函数外部使用static,静态存储期、文件作用域、内部链接,未显式初始化则字节为0