Linux入门DAY11
2026/8/2 4:11:14 网站建设 项目流程

#嵌入式开发基础##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. 核心底层特性

  1. 函数内部执行sizeof(a),得到的是指针占用字节(64 位系统为 8 字节),无法计算原数组真实长度,因此必须手动传入长度参数;
  2. 数组传递的是地址,函数内修改数组元素,会同步修改外部原始数组;
  3. 数组名仅代表数组首元素地址,不支持整体赋值操作。

二、函数与一维字符型数组(字符串)

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. 标识符必须先定义,后使用
  2. 同一层级作用域中,不允许定义同名变量;
  3. 嵌套作用域存在同名变量时,内层屏蔽外层变量。

(二)生命周期:变量内存存在的时长(时间维度)

1. 动态生命周期(普通 auto 局部变量)
  • 内存开辟:程序执行到变量定义代码时,在栈区分配内存;
  • 内存销毁:跳出当前{}代码块,栈内存自动回收释放;
  • 初始值特性:未手动初始化时,存储随机脏数据。
2. 静态生命周期(全局变量 /static 修饰局部变量)
  • 内存开辟:程序加载运行阶段提前分配内存;
  • 内存销毁:整个程序运行结束后统一释放;
  • 初始值特性:未手动初始化时,系统自动赋值为 0;
  • 存储区域:数据段,不存放在栈区。

六、变量四大存储类型修饰符

语法标准格式:存储类型 数据类型 变量名;

1. auto(默认修饰符)

所有普通局部变量默认自带 auto 关键字,日常编码可省略不写;变量存储在栈区,拥有动态生命周期,跳出代码块自动销毁。

auto int num = 10; // 等价写法,效果完全一致 int num = 10;

2. static(三大核心用途,面试高频考点)

  1. 修饰局部变量
    • 生命周期升级为静态生命周期,程序结束才释放内存;
    • 作用域不改变,依旧仅当前代码块内部可见;
    • 仅在第一次执行定义代码时初始化,函数多次调用会保留上一次变量值;
  2. 修饰全局变量
    • 限制变量作用域,仅当前.c源文件内部可用,外部文件无法通过extern导入;
  3. 修饰函数
    • 限定函数仅本文件内调用,其他源文件无法访问该函数。
  4. register(寄存器变量)

  5. 作用:向编译器建议将变量存入 CPU 寄存器,减少内存读写开销,提升运行速度;
  6. 关键限制:仅为编译器优化建议,编译器可忽略;寄存器无内存地址,无法使用取地址符&

register int i; // 下方代码编译报错,寄存器变量不能取地址 // int *p = &i;

4. extern(外部声明修饰符)

  1. 修饰全局变量:告知编译器该变量实际定义在其他源文件,允许当前文件跨文件访问;
  2. 修饰函数:声明其他源文件中已实现的函数,无需在当前文件重复编写函数体。

七、程序内存分区详解

分区层级(高地址→低地址)

  1. 内核区:操作系统专属内存区域,用户自定义代码无读写权限;
  2. 栈区 (stack):存放 auto 局部变量、函数形参;函数调用时分配内存,执行完毕自动释放;
  3. 堆区 (heap):由程序员通过malloc/free手动申请、释放内存;
  4. 数据区
    • .data段:存放已初始化的全局变量、static 静态变量;
    • .bss段:存放未初始化全局变量、static 静态变量,程序加载时系统自动清零;
    • .rodata只读常量区:存放字符串常量、const 只读常量;
  5. 文本区 (.text):存放编译后的二进制机器指令代码;
  6. CPU 寄存器:硬件高速存储,register 修饰的变量优先存入。

全局 / 静态变量统一特性汇总

  1. 存储位置:数据区,拥有静态生命周期;
  2. 未初始化默认值为 0;
  3. static 修饰局部变量:局部作用域 + 静态生命周期;
  4. static 修饰全局变量 / 函数:文件私有,禁止跨文件访问。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询