#嵌入式开发基础##Linux##C语言#
前言
本篇承接前面数组、函数基础内容,聚焦函数和各类数组传参、变量作用域 / 生命周期、内存分区、存储修饰符 static/auto/register/extern,是 C 语言入门到进阶分水岭,面试高频考点,全文结合底层内存图解、标准代码拆解。
一、函数与一维整型数组
1. 数组作为函数参数的定义语法
数组传参本质传递数组首元素地址,两种形参写法完全等价:
// 写法1:数组形式(可读性更强,推荐) void print_array(int a[], int len);
// 写法2:底层指针等价形式 void print_array(int *a, int len);
2. 数组函数标准调用方式
int arr[10] = {1,2,3,4,5};
int length = sizeof(arr)/sizeof(arr[0]);
print_array(arr, length);
3. 核心底层特性
- 函数内部执行
sizeof(a),得到的是指针占用字节(64 位系统为 8 字节),无法计算原数组真实长度,因此必须手动传入长度参数; - 数组传递的是地址,函数内修改数组元素,会同步修改外部原始数组;
- 数组名仅代表数组首元素地址,不支持整体赋值操作。
二、函数与一维字符型数组(字符串)
1. 字符串数组传参基础语法
void print_str(char str[]);
2. 和整型数组传参核心区别
- 无需手动传递长度参数:字符串末尾自带
\0结束标记,函数内依靠\0终止遍历; - 形参
sizeof(str)依旧返回指针大小(8 字节),仅靠结束符判断字符串边界。
三、函数与二维整型数组
1. 二维数组传参硬性语法规则
定义形参时行数可省略,列数必须固定,省略列数编译器无法识别内存排布:
// 合法标准写法 void print_2D(int a[][4], int row);
// 非法写法,编译报错
// void print_2D(int a[][], int row);
四、函数与二维字符型数组
1. 二维字符数组作用
存储多组独立字符串,每行代表一条完整字符串,列数限制单行最大字符容量。
char str[3][100] = {"hello", "world", "c language"};
五、变量的作用域 & 生命周期(C 语言重难点)
(一)作用域:变量可访问的范围(空间维度)
1. 局部变量
- 定义位置:函数内部、代码块
{}内部、函数形参; - 访问限制:仅当前
{}代码块内部可访问,代码块外部无法使用; - 同名覆盖规则:内层代码块定义和外层同名变量,遵循就近原则,外层变量在内层不可见。
2. 全局变量
- 定义位置:所有函数外部,源文件最顶层;
- 访问范围:当前源文件全部函数均可访问,其他
.c文件通过extern声明后可跨文件访问。
3. 通用规则
- 标识符必须先定义,后使用;
- 同一层级作用域中,不允许定义同名变量;
- 嵌套作用域存在同名变量时,内层屏蔽外层变量。
(二)生命周期:变量内存存在的时长(时间维度)
1. 动态生命周期(普通 auto 局部变量)
- 内存开辟:程序执行到变量定义代码时,在栈区分配内存;
- 内存销毁:跳出当前
{}代码块,栈内存自动回收释放; - 初始值特性:未手动初始化时,存储随机脏数据。
2. 静态生命周期(全局变量 /static 修饰局部变量)
- 内存开辟:程序加载运行阶段提前分配内存;
- 内存销毁:整个程序运行结束后统一释放;
- 初始值特性:未手动初始化时,系统自动赋值为 0;
- 存储区域:数据段,不存放在栈区。
六、变量四大存储类型修饰符
语法标准格式:存储类型 数据类型 变量名;
1. auto(默认修饰符)
所有普通局部变量默认自带 auto 关键字,日常编码可省略不写;变量存储在栈区,拥有动态生命周期,跳出代码块自动销毁。
auto int num = 10; // 等价写法,效果完全一致 int num = 10;2. static(三大核心用途,面试高频考点)
- 修饰局部变量
- 生命周期升级为静态生命周期,程序结束才释放内存;
- 作用域不改变,依旧仅当前代码块内部可见;
- 仅在第一次执行定义代码时初始化,函数多次调用会保留上一次变量值;
- 修饰全局变量
- 限制变量作用域,仅当前
.c源文件内部可用,外部文件无法通过extern导入;
- 限制变量作用域,仅当前
- 修饰函数
- 限定函数仅本文件内调用,其他源文件无法访问该函数。
register(寄存器变量)
- 作用:向编译器建议将变量存入 CPU 寄存器,减少内存读写开销,提升运行速度;
- 关键限制:仅为编译器优化建议,编译器可忽略;寄存器无内存地址,无法使用取地址符
&;
register int i; // 下方代码编译报错,寄存器变量不能取地址 // int *p = &i;
4. extern(外部声明修饰符)
- 修饰全局变量:告知编译器该变量实际定义在其他源文件,允许当前文件跨文件访问;
- 修饰函数:声明其他源文件中已实现的函数,无需在当前文件重复编写函数体。
七、程序内存分区详解
分区层级(高地址→低地址)
- 内核区:操作系统专属内存区域,用户自定义代码无读写权限;
- 栈区 (stack):存放 auto 局部变量、函数形参;函数调用时分配内存,执行完毕自动释放;
- 堆区 (heap):由程序员通过
malloc/free手动申请、释放内存; - 数据区
.data段:存放已初始化的全局变量、static 静态变量;.bss段:存放未初始化全局变量、static 静态变量,程序加载时系统自动清零;.rodata只读常量区:存放字符串常量、const 只读常量;
- 文本区 (.text):存放编译后的二进制机器指令代码;
- CPU 寄存器:硬件高速存储,register 修饰的变量优先存入。
全局 / 静态变量统一特性汇总
- 存储位置:数据区,拥有静态生命周期;
- 未初始化默认值为 0;
- static 修饰局部变量:局部作用域 + 静态生命周期;
- static 修饰全局变量 / 函数:文件私有,禁止跨文件访问。