嵌入式面试高频(5)!!!C++语言(嵌入式八股文,嵌入式面经)

C++有几种传值方式之间的区别

一、值传递(Pass by Value)

  • 机制:创建参数的副本,函数内操作不影响原始数据
  • 语法void func(int x)
  • 特点
    • 数据安全:原始数据不受影响
    • 性能开销:需要复制大对象(如结构体、类)
    • 示例
void increment(int x) { x++; } // 修改副本,不影响原始值
int a = 10;
increment(a); // a仍为10引用高效移动资源

 

二、指针传递(Pass by Pointer)

  • 机制:传递变量的地址,函数通过指针间接操作原始数据
  • 语法void func(int* ptr)
  • 特点
    • 可修改原始数据:通过*ptr修改
    • 空指针风险:需检查ptr != nullptr
    • 示例
void increment(int* ptr) { if (ptr) (*ptr)++; // 安全检查
}
int a = 10;
increment(&a); // a变为11

 

三、引用传递(Pass by Reference)

  • 机制:传递变量的别名,函数直接操作原始数据
  • 语法void func(int& ref)
  • 特点
    • 可修改原始数据:直接操作引用
    • 安全性:引用必须初始化,无空引用
    • 示例
void increment(int& ref) { ref++; } // 直接操作原始值
int a = 10;
increment(a); // a变为11

 

四、核心区别对比

特性值传递指针传递引用传递
操作对象副本原始数据(通过地址)原始数据(通过别名)
是否修改原值
语法复杂度简单(直接传值)较复杂(需解引用)简单(类似值传递)
空值风险有空指针风险无(必须初始化)
典型用途简单数据、只读操作需显式传递地址、可空对象参数、避免拷贝

五、示例对比 

// 值传递
void passByValue(int val) { val = 20; } // 不影响原始值// 指针传递
void passByPointer(int* ptr) { if (ptr) *ptr = 20; // 需检查空指针
}// 引用传递
void passByReference(int& ref) { ref = 20; } // 直接修改int main() {int x = 10;passByValue(x);     // x仍为10passByPointer(&x);  // x变为20passByReference(x); // x变为20return 0;
}

 

六、C++11 新增:右值引用(Move Semantics)

  • 机制:专门处理临时对象(右值)的引用,避免深拷贝
  • 语法void func(Type&& rvalue)
  • 典型用途:移动构造函数、移动赋值运算符
  • 示例
std::vector<int> createVector() {return std::vector<int>{1,2,3};
}std::vector<int> vec = createVector(); // 通过右值引用高效移动资源

 二.数组指针与指针数组的区别

一、核心区别

特性数组指针(Pointer to Array)指针数组(Array of Pointers)
本质指针:指向一个数组数组:存储多个指针
语法int (*ptr)[5];(括号强制 ptr 为指针)int* arr[5];(arr 先与 [] 结合为数组)
指向对象整个数组数组的元素(每个元素是一个指针)
指针运算ptr + 1 跳过整个数组(如 5 个 int)arr + 1 指向下一个元素(下一个指针)
典型用途传递多维数组、精确控制内存布局管理多个动态分配的对象、字符串数组

二、语法对比

1. 数组指针(指向数组的指针) 

int arr[5] = {1,2,3,4,5};
int (*ptr)[5] = &arr;  // 指向包含5个int的数组// 访问元素
(*ptr)[0] = 10;  // 修改arr[0]为10

2. 指针数组(包含指针的数组) 

 

int a = 1, b = 2, c = 3;
int* arr[3] = {&a, &b, &c};  // 数组的每个元素是int*// 访问元素
*arr[0] = 10;  // 修改a为10

 三、内存布局差异

1. 数组指针 

ptr ──> [1, 2, 3, 4, 5]  // 指向整个数组

 

  • ptr 存储整个数组的起始地址
  • sizeof(ptr) 为指针大小(通常 4/8 字节)

2. 指针数组 

arr ──> [&a, &b, &c]     // 数组元素为指针│    │    │▼    ▼    ▼a    b    c

 

  • arr 是一个数组,包含多个指针
  • sizeof(arr) 为 3 * sizeof(int*)

四、典型应用场景

1. 数组指针的应用
// 传递多维数组
void printMatrix(int (*matrix)[4], int rows) {for (int i = 0; i < rows; i++) {for (int j = 0; j < 4; j++) {printf("%d ", matrix[i][j]);}printf("\n");}
}int main() {int matrix[3][4] = {...};printMatrix(matrix, 3);  // matrix退化为int (*)[4]
}

 2. 指针数组的应用

// 字符串数组
const char* fruits[3] = {"Apple","Banana","Cherry"
};// 动态内存管理
int* ptrs[5];
for (int i = 0; i < 5; i++) {ptrs[i] = new int(i);
}

 

五、常见混淆点

1. 括号位置决定类型

 

int (*ptr)[5];  // 数组指针:ptr是指向包含5个int的数组的指针
int* ptr[5];    // 指针数组:ptr是包含5个int*的数组
2. 数组名 vs 数组指针
int arr[5];
int* ptr1 = arr;      // 指向首元素的指针(隐式转换)
int (*ptr2)[5] = &arr; // 指向整个数组的指针printf("%p\n", arr);     // 数组首元素地址
printf("%p\n", &arr);    // 整个数组的地址(数值相同,但类型不同)
printf("%p\n", arr + 1); // 跳过1个元素
printf("%p\n", &arr + 1); // 跳过整个数组(5个元素)

 三.指针函数与函数指针的区别

一、核心区别

特性指针函数(Function Returning Pointer)函数指针(Pointer to Function)
本质函数:返回值为指针类型指针:指向一个函数
语法int* func(int a);(返回 int*)int (*ptr)(int a);(ptr 为指针)
用途返回动态分配的内存或全局变量地址作为参数传递函数、实现回调机制
调用方式int* result = func(10);int val = (*ptr)(10); 或 ptr(10);

 

二、语法对比

1. 指针函数(返回指针的函数)
int* createArray(int size) {int* arr = new int[size];for (int i = 0; i < size; i++) {arr[i] = i;}return arr;  // 返回动态分配的数组指针
}// 调用
int* ptr = createArray(5);
2. 函数指针(指向函数的指针)
int add(int a, int b) { return a + b; }// 定义函数指针并初始化
int (*op)(int, int) = add;// 调用方式1
int result = (*op)(3, 4);  // 显式解引用// 调用方式2(C++允许隐式解引用)
int result2 = op(3, 4);    // 等价于上一行

 

三、典型应用场景

1. 指针函数的应用
// 返回静态变量的地址
const char* getMessage() {static const char* msg = "Hello";return msg;
}

 2. 函数指针的应用

// 回调函数示例
void process(int a, int b, int (*func)(int, int)) {int result = func(a, b);printf("Result: %d\n", result);
}int main() {int (*add)(int, int) = [](int a, int b) { return a + b; };process(3, 4, add);  // 输出7
}

 

四、常见混淆点

1. 括号位置决定类型
int* func(int a);  // 指针函数:返回int*
int (*ptr)(int a); // 函数指针:ptr指向返回int的函数

 2. 函数指针作为参数

// 排序函数接受比较函数指针
void sort(int* arr, int size, bool (*compare)(int, int)) {// 排序逻辑...
}bool ascending(int a, int b) { return a < b; }// 调用
sort(array, 10, ascending);

 四.malloc和calloc的区别

 

一、核心区别

特性malloccalloc
初始化不初始化分配的内存(内容随机)将内存初始化为 0
参数单个参数:所需内存字节数两个参数:元素数量和元素大小
原型void* malloc(size_t size);void* calloc(size_t num, size_t size);
性能略快(无需初始化)略慢(需清零内存)

二、示例对比

1. malloc 的使用

 

int* ptr = (int*)malloc(5 * sizeof(int));  // 分配5个int的内存
if (ptr != NULL) {// 内存内容未初始化,可能包含随机值for (int i = 0; i < 5; i++) {printf("%d ", ptr[i]);  // 输出随机值}
}
2. calloc 的使用
int* ptr = (int*)calloc(5, sizeof(int));  // 分配5个int的内存并初始化为0
if (ptr != NULL) {// 内存内容已初始化为0for (int i = 0; i < 5; i++) {printf("%d ", ptr[i]);  // 输出: 0 0 0 0 0}
}

 三、内存布局差异

 

// malloc分配的内存(未初始化)
ptr ──> [随机值][随机值][随机值][随机值][随机值]// calloc分配的内存(初始化为0)
ptr ──> [0][0][0][0][0]

四、安全与性能考量

  1. 安全性

    • calloc适合需要初始化的场景(如存储结构体、数组)
    • malloc需手动初始化(如使用memset):
int* ptr = malloc(5 * sizeof(int));
memset(ptr, 0, 5 * sizeof(int));  // 手动清零

 

  1. 性能calloc因初始化操作会稍慢

    • 大数据块初始化可能影响性能

五、典型应用场景

场景推荐函数原因
存储需要初始化的数据calloc自动清零,避免未定义行为
存储无需初始化的数据malloc略高效
分配二进制缓冲区malloc后续会写入数据,无需提前初始化
分配结构体数组calloc确保结构体成员初始化为有效值

 五.内存泄漏,如何检测和避免?

一、什么是内存泄漏?

  • 定义:程序动态分配的内存(如malloc/new)未被正确释放(如free/delete),导致这部分内存永久无法被回收
  • 危害
    • 随着程序运行,可用内存逐渐减少
    • 最终导致系统性能下降、程序崩溃或系统崩溃

二、内存泄漏的常见原因

  1. 忘记释放内存

 

void func() {int* ptr = new int[100];  // 分配内存// 忘记调用delete[] ptr;
}

异常导致路径未释放

void func() {int* ptr = new int[100];if (condition) {throw std::exception();  // 异常退出,未释放内存}delete[] ptr;
}

 指针覆盖

int* ptr = new int;
ptr = new int;  // 原内存丢失,无法释放

 循环分配内存

while (true) {int* ptr = new int[1000];  // 持续分配,无释放
}

 类中未定义析构函数

class Resource {
public:Resource() { data = new int[100]; }// 未定义析构函数释放data
private:int* data;
};

 

三、检测内存泄漏的方法

1. 静态代码分析工具
  • 工具:Cppcheck、Clang-Tidy、PC-Lint
  • 特点
    • 不运行程序,直接分析代码
    • 检测常见模式(如分配后未释放)
  • 示例命令

cppcheck --enable=all --inconclusive your_file.cpp

2. 动态内存分析工具
  • Valgrind(Linux)

  • valgrind --leak-check=full ./your_program

 

四、避免内存泄漏的最佳实践

1. RAII(资源获取即初始化)原则
  • 使用智能指针(C++):

    cpp

    运行

    #include <memory>void func() {std::unique_ptr<int[]> ptr(new int[100]);  // 自动释放// 无需手动delete
    }
    
2. 容器替代原始数组

cpp

运行

#include <vector>void func() {std::vector<int> data(100);  // 自动管理内存
}
3. 异常安全
  • 使用try-catch确保资源释放:

    cpp

    运行

    void func() {int* ptr = new int[100];try {// 可能抛出异常的代码} catch (...) {delete[] ptr;throw;}delete[] ptr;
    }
    
4. 遵循配对原则
  • malloc → free
  • new → delete
  • new[] → delete[]
5. 避免指针浅拷贝
  • 使用深拷贝或禁用拷贝构造函数
  • 使用智能指针的移动语义
6. 代码审查
  • 重点检查:
    • 长时间运行的程序(如服务器)
    • 循环中的内存分配
    • 复杂函数中的多条返回路径

五、高级技术

1. 内存池(Memory Pool)
  • 预先分配大块内存,按需分配小块,减少系统调用
  • 避免频繁分配 / 释放导致的碎片
2. 智能指针的使用场景
类型用途
std::unique_ptr独占所有权
std::shared_ptr共享所有权(引用计数)
std::weak_ptr弱引用,避免循环引用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/83981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark 之 AQE

个人其他链接 AQE 执行顺序https://blog.csdn.net/zhixingheyi_tian/article/details/125112793 AQE 产生 AQE 的 循环触发点 src/main/scala/org/apache/spark/sql/execution/adaptive/AdaptiveSparkPlanExec.scala override def doExecute(): RDD[InternalRow] = {withFin…

FSMC扩展外部SRAM

提示&#xff1a;文章 文章目录 前言一、背景二、2.12.2 三、3.1 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 2025年6月7日 19:34:48 今天看了FSMC扩展外部SRAM的文章&#xff0c;大概理解到stm32除了内部存储器&#xff0c;还可以扩展外部存储器。其中s…

【CSS-6】深入理解CSS复合选择器:提升样式表的精确性与效率

CSS选择器是前端开发的基石&#xff0c;而复合选择器则是其中最强大且实用的工具之一。本文将全面解析CSS复合选择器的类型、用法、优先级规则以及最佳实践&#xff0c;帮助你编写更高效、更精确的样式表。 1. 什么是复合选择器&#xff1f; 复合选择器是通过组合多个简单选择…

使用python实现奔跑的线条效果

效果&#xff0c;展示&#xff08;视频效果展示&#xff09;&#xff1a; 奔跑的线条 from turtle import * import time t1Turtle() t2Turtle() t3Turtle() t1.hideturtle() t2.hideturtle() t3.hideturtle() t1.pencolor("red") t2.pencolor("green") t3…

从零搭建uniapp项目

目录 创建uni-app项目 基础架构 安装 uni-ui 组件库 安装sass依赖 easycom配置组件自动导入 配置view等标签高亮声明 配置uni-ui组件类型声明 解决 标签 错误 关于tsconfig.json中提示报错 关于非原生标签错误&#xff08;看运气&#xff09; 安装 uview-plus 组件库…

Redis主从复制的原理一 之 概述

概述 本文概要性的介绍了Redis主从复制原理&#xff0c;及新旧版本主从复制的区别&#xff0c;优缺点。具体的主从复制过程可详见「Redis主从复制原理二 之 主从复制工作流程」 旧版主从复制的实现 Redis的复制功能分为 同步&#xff08;sync&#xff09;和 命令传播&#xff…

网络原理 4-TCP3

上篇文章&#xff0c;我们讲了TCP协议的连接管理&#xff08;”三次握手“和”四次挥手“的过程&#xff09;。 4、滑动窗口 这个滑动窗口是TCP中非常有特点的机制。我们知道&#xff0c;TCP是通过前面讲的三个机制&#xff1a;确认应答&#xff0c;超时重传&#xff0c;连接…

【使用 Loki + Promtail + Grafana 搭建轻量级容器日志分析平台】

使用 Loki Promtail Grafana 搭建轻量级容器日志分析平台 摘要 本文介绍如何通过 Docker Compose 快速搭建 Loki 日志存储、Promtail 日志采集和 Grafana 日志可视化/告警的完整流程。用最小化示例演示核心配置、常见问题排查和告警规则设置&#xff0c;帮助读者快速上手。…

CRMEB 中 PHP 快递查询扩展实现:涵盖一号通、阿里云、腾讯云

目前已有一号通快递查询、阿里云快递查询扩展 扩展入口文件 文件目录 crmeb\services\express\Express.php 默认一号通快递查询 namespace crmeb\services\express;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use think\Container; use thi…

使用 Python 自动化 Word 文档样式复制与内容生成

在办公自动化领域&#xff0c;如何高效地处理 Word 文档的样式和内容复制是一个常见需求。本文将通过一个完整的代码示例&#xff0c;展示如何利用 Python 的 python-docx 库实现 Word 文档样式的深度复制 和 动态内容生成&#xff0c;并结合知识库中的最佳实践优化文档处理流程…

【MATLAB代码】基于MCC(最大相关熵)的EKF,一维滤波,用于解决观测噪声的异常|附完整代码,订阅专栏后可直接查看

本文所述的代码实现了一种基于最大相关熵准则(Maximum Correntropy Criterion, MCC)的鲁棒性卡尔曼滤波算法(MCC-KF),重点解决传统卡尔曼滤波在观测噪声存在异常值时估计精度下降的问题。通过引入高斯核函数对残差进行加权处理,有效降低了异常观测值对状态估计的干扰。订…

46、web实验-遍历数据与页面bug修改

46、web实验-遍历数据与页面bug修改 在Web开发中&#xff0c;遍历数据和修改页面bug是常见的任务。以下是关于这两个主题的讲解&#xff1a; ### 一、遍历数据 **目的**&#xff1a;在页面上动态展示数据&#xff0c;例如用户列表、商品信息等。 **常用方法**&#xff1a; ####…

华为云Flexus+DeepSeek征文|体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建自己的自定义聊天助手

华为云FlexusDeepSeek征文&#xff5c;体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建自己的自定义聊天助手 什么是华为云ModelArts 华为云ModelArts ModelArts是华为云提供的全流程AI开发平台&#xff0c;覆盖从数据准备到模型部署的全生命周期管理&#xff0c;帮助…

Qwen大语言模型里,<CLS>属于特殊的标记:Classification Token

Qwen大语言模型里,<CLS>属于特殊的标记:Classification Token 目录 Qwen大语言模型里,<CLS>属于特殊的标记:Classification Token功能解析工作机制应用场景举例说明技术要点在自然语言处理(NLP)领域 都是<CLS> + <SEP>吗?一、CLS和SEP的作用与常见用法1. **CLS标…

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…

JAVA毕业设计224—基于Java+Springboot+vue的家政服务系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue的家政服务系统(源代码数据库)224 一、系统介绍 本项目前后端分离&#xff0c;分为用户、家政人员、管理员三种角色 1、用户&#xff1a; 登录、注册、轮播…

滴滴 服务端 面经

一、缓存与数据库的使用场景及性能差异 1. 缓存的适用场景 高频读、低频写场景&#xff1a;如商品详情页、用户信息等读多写少的数据&#xff0c;减少数据库压力。实时性要求不高的数据&#xff1a;如首页推荐列表、统计数据&#xff08;非实时更新&#xff09;&#xff0c;允…

linux操作系统---网络协议

目录 案例演练----网络搭建 路由启配置 多个路由情况下如何联通 静态路由 案例演练----网络搭建 Cisco交换机的命令行用户模式1 switch> 特权模式1 switch>enable disable回到用户模式 2 switch#全局配置模式1 switch#config terminal 2 switch(co…

华为OD机试_2025 B卷_计算某个字符出现次数(Python,100分)(附详细解题思路)

文章目录 题目描述字符计数解析&#xff1a;简单高效的统计方法核心解题思路完整代码实现应用场景扩展 题目描述 写出一个程序&#xff0c;接受一个由字母、数字和空格组成的字符串&#xff0c;和一个字符&#xff0c;然后输出"输入字符串&#xff08;第二行输入的字符&a…

华为仓颉语言初识:并发编程之同步机制(上)

前言 线程同步机制是多线程下解决线程对共享资源竞争的主要方式&#xff0c;华为仓颉语言提供了三种常见的同步机制用来保证线程同步安全&#xff0c;分别是原子操作&#xff0c;互斥锁和条件变量。本篇文章详细介绍主要仓颉语言解决同步机制的方法&#xff0c;建议点赞收藏&a…