学嵌入式和C语言编程|学习日记Day11:各类数组作函数参数、变量作用域、生命周期、存储类别
前言
今天继续拓展函数传参,学习一维字符数组、二维整型数组、二维字符数组作为函数参数的规则;然后学习变量的作用域、生命周期,还有auto、static、register、extern四种存储类型。
在嵌入式开发当中,局部、全局、static 静态变量使用频率非常高,直接关系到外设状态保存、多文件工程开发,是嵌入式 C 的核心重点。
一、不同数组作为函数参数
1. 一维字符型数组做函数参数
函数定义格式
c |
调用格式
c |
注意要点
- 一维字符数组传参只传递数组名即可,不需要传入长度;字符串末尾自带'\0'结束标记,函数内部依靠\0判断字符串结束。
- 本质传递依旧是数组首元素地址,函数内部修改数组内容,外部原始数组会跟着改变。
- ⚠️在被调函数内部执行sizeof(数组形参),得到的是地址所占内存大小,不是数组真实总字节。
2. 二维整型数组做函数参数
函数定义格式
c |
调用格式
c |
注意要点
- 二维整型数组传参,形参列数必须写明,行数可以省略。
- 函数内部无法通过sizeof自动计算行数,行数需要当做实参手动传入;列数可以在函数内通过sizeof(a[0]) / sizeof(a[0][0])计算得到。
3. 二维字符型数组做函数参数
函数定义格式
c |
调用格式
c |
各类数组传参汇总表
数组类型 | 函数形参写法 | 是否需要传入长度 | 传递本质 |
一维 int 数组 | int arr[] , int len | ✅必须传入数组长度 | 首元素地址 |
一维 char 数组 | char str[] | ❌不需要,依靠\0结束符 | 首元素地址 |
二维 int 数组 | int arr[][列] , int row | ✅传入行数;列数代码内计算 | 数组首行地址 |
二维 char 数组 | char str[][列] , int row | ✅传入行数 | 数组首行地址 |
二、变量的作用域(空间角度)
作用域:标识符、变量能够被访问、使用的代码范围。
- 局部作用域:写在大括号{}内部,函数内部定义的变量、形参,只能够在大括号内部访问。
- 全局作用域:写在所有函数外面,整个工程都可以访问,例如函数名、全局变量。
嵌套作用域规则:如果内外出现同名标识符,外层变量在内层不可见(就近原则)。 |
语法强制要求:变量必须先定义,后使用;同一个作用域,不能定义名字相同的变量。 |
三、变量的生命周期(时间角度)
生命周期:变量内存开辟,直到内存被回收的完整存活时间。
- 动态生命周期:局部变量。走到变量定义处开辟内存;离开作用域,内存立刻回收。
- 静态生命周期:和整个程序运行时间保持一致。程序启动开辟内存,程序结束才释放内存。全局变量、static 静态变量属于静态生命周期。
局部变量、全局变量、static 静态变量对比
变量类型 | 作用域 | 生命周期 | 存储位置 | 未初始化默认值 |
局部普通变量 | 仅限当前大括号内部 | 动态生命周期,出作用域销毁 | 栈区 | 随机垃圾值 |
全局变量 | 整个程序全局可见 | 静态生命周期,程序结束销毁 | 数据段 /.bss 段 | 系统默认 0 |
static 局部静态变量 | 仅限局部大括号内部 | 静态生命周期,程序结束销毁 | 数据段 /.bss 段 | 系统默认 0 |
补充:
- 未初始化的全局变量、static 静态变量存放在.bss段,系统自动清零;
- 已经初始化完成的全局、static 静态变量存放在.data段。
四、四种存储类型修饰符
完整格式:存储类型 数据类型 变量名;
1. auto
- 默认存储类型,日常写局部变量默认就是 auto,一般省略不写。
- 具备局部变量动态生命周期,存储在栈区。
2. static 静态修饰符
static 有三层作用
- 修饰局部变量:变量变成静态生命周期,依旧保留局部作用域,出大括号不会销毁,值会保留。
- 修饰函数:该函数只允许当前.c 源文件内部调用,别的源文件无法访问。
- 修饰全局变量:该全局变量仅限当前源文件内部使用,外部其他.c文件无法访问。
嵌入式常用场景:按键计数、状态标记,用 static 局部变量保存上一次状态,函数多次调用之间保留数值。 |
3. register 寄存器变量
- 只是给编译器建议:尽量把该变量放到 CPU 寄存器中,提升运行速度,不是强制命令。
- 寄存器没有内存地址,不能对 register 变量取地址&。
4. extern 外部声明
- 修饰全局变量:声明外部别的.c文件定义的全局变量,允许本文件访问外部全局变量。
- 修饰函数:声明外部其他.c文件中的函数,本文件可以调用外部函数。
今日学习总结
- 一维字符数组传参不用传长度,依靠字符串结束符\0;二维数组传参,列数绝对不能省略。
- 作用域看空间,生命周期看时间;局部变量栈区分配,出大括号销毁;全局、static 静态变量程序全程存在。
- static 修饰局部变量:作用域不变,生命周期改为静态,函数多次调用之间保留数值。
- static 修饰函数、全局变量,限制作用域为本.c文件;extern 用来引用别的文件的全局变量和函数,是多文件嵌入式工程必备语法。
- register 只是建议放寄存器,不能取地址;auto 是局部变量默认属性,通常省略。