嵌入式大厂面经 6(持续更新中!)
这是一个嵌入式大厂面试题专栏,每天更新高频面试题。专栏将包含题目描述、详细解析、相关知识点扩展以及实际代码示例。内容涵盖操作系统、驱动开发、通信协议等核心领域,并结合实际项目经验进行分析。每道题目都会附带面试官可能的追问方向,帮助大家更好地准备面试!
1. 内存对齐
基本概念
- CPU访问内存时,按照特定字节大小(对齐边界)进行访问
- 提高内存访问效率,但可能造成内存空间浪费
// 内存对齐示例 struct Example1 { // 不优化 char a; // 1字节 double b; // 8字节 int c; // 4字节 }; // 总大小24字节 struct Example2 { // 优化排序 double b; // 8字节 int c; // 4字节 char a; // 1字节 }; // 总大小16字节 // 指定对齐方式 #pragma pack(1) // 1字节对齐 struct Example3 { char a; double b; int c; }; // 总大小13字节 #pragma pack() // 恢复默认对齐
2. 内存泄漏
定义
- 程序申请的内存空间未被正确释放
- 导致可用内存逐渐减少
常见情况和解决方法
// 1. 常见内存泄漏 void badFunction(void) { int *p = (int*)malloc(sizeof(int)); return; // 忘记释放内存 } // 2. 正确的内存管理 void goodFunction(void) { int *p = (int*)malloc(sizeof(int)); // 使用内存 free(p); // 释放内存 p = NULL; // 避免悬空指针 } // 3. 智能指针思想(C++) class SmartPtr { int* ptr; public: SmartPtr(int* p) : ptr(p) {} ~SmartPtr() { delete ptr; } };
3. 数组名和指针
主要区别
- 本质不同数组名:表示整个数组的起始地址,是常量指针:可变的地址变量
- 内存分配数组:编译时分配连续空间指针:运行时可动态分配
void arrayPointerExample(void) { int arr[5] = {1, 2, 3, 4, 5}; int *ptr = arr; // 指针指向数组首地址 // 数组名不能被修改 // arr = ptr; // 错误:数组名是常量 ptr = arr; // 正确:指针可以修改 // 大小不同 printf("sizeof(arr) = %d\n", sizeof(arr)); // 输出20(5*4字节) printf("sizeof(ptr) = %d\n", sizeof(ptr)); // 输出4或8(指针大小) // 数组访问 printf("%d %d\n", arr[0], ptr[0]); // 两种方式等价 printf("%d %d\n", *(arr+1), *(ptr+1)); // 指针运算等价 }
关键注意点
- 数组作为函数参数
// 数组作为参数会退化为指针 void function1(int arr[]) { // sizeof(arr)此时等于指针大小 } // 建议使用指针+大小的方式 void function2(int *arr, int size) { for(int i = 0; i < size; i++) { // 处理数组元素 } }
- 二维数组和指针
void twoDimensionExample(void) { int arr[3][4]; int (*p)[4] = arr; // 数组指针 // 访问方式 arr[1][2] = 10; // 数组方式 *(*(p + 1) + 2) = 10; // 指针方式 }
这些概念在C语言中都非常重要,正确理解和使用它们可以帮助我们写出更高效、更可靠的代码。
嵌入式面试八股文全集 文章被收录于专栏
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。