C++细节,可能存在的隐患,面试题03

文章目录

  • 11. C++编译过程
  • 12. const vs #define
    • 12.1. 全局const vs 局部const
  • 13. C++内存分区
  • 14. C++变量作用域
    • 14.1. 常量 vs 全局变量 vs 静态变量
  • 15. C++类型转换
  • 16. 函数指针
  • 17. 悬空指针 vs 野指针
  • 18. 为什么使用空指针,建议使用nullptr而不是NULL?

11. C++编译过程

  • 预处理:处理以#开头的预处理指令,比如#include和#define等。
  • 编译:将预处理后的源文件转汇编代码。
  • 汇编:将汇编代码转机器指令,生成目标文件。
  • 链接:将目标文件与相应的库文件进行链接,生成可执行文件。

12. const vs #define

//都可以定义常量。
#define MAX_SIZE 100
const int value = 50;

  • 处理阶段:
    • #define在预处理阶段进行替换。
    • const在编译阶段确定其值。
  • 类型安全:
    • #define只是简单的字符串替换,不进行类型检查,存在隐患。
    • const有数据类型,在编译时进行类型检查。
  • 存储方式:
    • #define有多少次替换,在内存中有多少个拷贝。
    • const分配内存空间,且在程序运行过程中内存只有一个拷贝。
  • 调试信息:
    • #define只是替换,不会产生调试信息。
    • const被视为变量,可以产生调试信息。如下图。
      在这里插入图片描述

12.1. 全局const vs 局部const

  • 全局const存储在常量区,无法通过指针修改。
  • 局部const存储在栈区,是一个“假”常量,始终是一个变量,只是编译时进行语法检查,发现代码有对const修饰的变量修改时则报错。本质上时可以修改的,利用指针获取变量地址,强制将const属性修饰去掉,就可以修改对应内容,【注意】 会造成未定义行为。代码如下。
void print(const int& a)
{
    cout << a << endl;
}

int main() {
  
    const int num = 50; //局部const
    int* p = const_cast<int*>(&num); //使用const_cast<>强制将const属性去掉
    *p = 20; //通过指针修改内容

    print(num);
    return 0;
}
  • 程序执行结果,如下图。

在这里插入图片描述

  • 分析:当print()函数的参数是引用或指针时,会传入修改后的const内容,而不会因为编译器的优化,即常量折叠,在编译时就替换。这是不当的操作。

13. C++内存分区

  • 堆:用于动态分配内存,使用new或malloc手动分配,使用delete或free手动释放,注意内存泄漏的问题。
  • 栈:存储局部变量和函数调用的控制信息,如返回地址、参数、局部变量等,由系统自动分配和释放。
  • 全局区:存放全局变量、静态变量,程序结束后由系统释放。
  • 常量区:存放字符串常量等,程序结束后由系统释放。
  • 代码区:存放程序的二进制代码。

14. C++变量作用域

  • 全局变量属于进程作用域,在整个进程中都可以访问到。
  • 静态变量属于文件作用域,在当前源码文件内可以访问到。
  • 局部变量属于函数作用域,在函数内可以访问到。
  • 在’{ }'语句块内定义的变量属于块作用域,只能在该块内访问。

14.1. 常量 vs 全局变量 vs 静态变量

  • 相同:程序执行前就存在了,即在编译期就已经确定了地址。通过立即数访问。
  • 不同:作用域和内存分配
    • 常量
      • 全局常量,存放在常量区(只读数据段),整个文件内都可以访问到。
      • 局部常量,存放在栈区,在函数内可以访问到。
    • 全局变量,存放在全局区(可读写数据段),整个文件内都可以访问到。
    • 静态变量
      • 全局静态变量,存放在全局区(可读写数据段),当前文件内可以访问到。
      • 局部静态变量,存放在全局区(可读写数据段),在函数内可以访问到。

15. C++类型转换

  • 隐式类型转换由编译器自动完成
    • char,short——>int——>unsigned——>long——>double
    • float ——>double
  • 显式类型转换手工强制完成
    • 使用()
    • 标准转型操作符,能够避免许多任意转型引起的潜在错误,如下。
  1. const_cast:去除或添加const、volatile属性。
int num = 42; 
const int* p = const_cast<const int*>(&num); //添加const修饰
  1. static_cast:用于常规类型转换,如数值之间的转换、指针或引用之间的转换。
double d = 3.14;
int i = static_cast<int>(d); //将double转int
  1. dynamic_cast:用于多态对象(即存在虚函数的对象)间类型转换,将基类指针或引用转换为子类指针或引用,从而访问子类特有的成员函数。【注意】 引用转型失败会抛异常”bad_cast“;指针转型失败会返回一个空指针,如果漏写检查代码(assert/if语句)会导致安全隐患。
class Draw
{
public:
    virtual ~Draw(){}
    virtual void drawLen() = 0;  
};

class Circle : public Draw
{
private:
    double radius; 
    
public:
    Circle(double r) : radius(r){}
    ~Circle() { printf("%s%f\n", "Delete circle with radius ",radius); }

    void getDescription() { printf("%s%f\n", "Circle with radius ",radius);}
    void drawLen() { printf("%s%f\n", "Circle with len ", 2 * 3.14 * radius); }
};

int main() 
{
    Draw* d = new Circle(5);  //基类指针指向子类对象
    d->drawLen();
 
    Circle* c = dynamic_cast<Circle*>(d); //将基类指针转子类指针
    if(c!=nullptr) 
   		 c->getDescription(); //访问子类特有的成员函数

    delete d; 
    return 0;
}

  1. reinterpret_cast:对目标的内存二进制位进行低层次的重新解释。如将指针转换为整数、不同类型的指针之间的转换。【注意】 它会忽略指针类型和数据之间的任何差异,存在安全隐患,因此需要谨慎使用。
int num = 20;
double* d = reinterpret_cast<double*>(&num); //将int*转double*

16. 函数指针

  • 函数调用是直接调用的;而函数指针是先取出指针的值(函数地址)再调用,是间接调用的。
  • 应用场景
    • 实现回调函数,比如在图形用户界面中,可以使用函数指针指定按钮点击事件的响应函数。
    • 把函数指针当形参传递给某些具有通用功能的模块,并封装成接口来提高代码的灵活性,方便后期维护。
    • 可以在排序和搜索算法中,使用函数指针提供自定义的比较逻辑,比如升序、降序,如下。
#include<iostream>
#include<vector>
using namespace std;

//定义比较函数指针类型
using CompareFunction = bool(*)(int, int);

// 冒泡排序,传入比较函数指针
void bubbleSort(vector<int>& arr, CompareFunction compare) {

    int n = arr.size();
    for (int i = 0; i < n - 1; ++i) 
        for (int j = 0; j < n - i - 1; ++j) 
            if (compare(arr[j], arr[j + 1])) 
                swap(arr[j], arr[j + 1]);
}

//升序
bool ascending(int a, int b) {return a > b;}

// 降序
bool descending(int a, int b) { return a < b;}

int main() 
{
    vector<int> numbers = { 5, 2, 8, 1, 4 };

    // 使用升序
    cout << "Ascending order:" << std::endl;
    bubbleSort(numbers, ascending);
    for (auto && u : numbers) { cout << u << " ";}

    // 使用降序
    cout << endl << "Descending order:" <<endl;
    bubbleSort(numbers, descending);
    for (auto&& u : numbers) { cout << u << " "; }

    return 0;
}
  • 程序执行结果,如下图。
    在这里插入图片描述

17. 悬空指针 vs 野指针

  • 悬空指针:当指向的内存被释放后,指针没有被及时置空。【注意】 访问悬空指针会导致未定义行为,如下。
int* ptr = new int(42);
delete ptr;

*ptr = 20; //错误,访问悬空指针会导致未定义行为。
  • 野指针:指针没有被初始化。【注意】 野指针的值是不确定的,可能指向任意的内存地址,访问野指针会导致未定义行为,如下。
 int* ptr;
 
*ptr = 20; //错误,访问野指针会导致未定义行为。

18. 为什么使用空指针,建议使用nullptr而不是NULL?

  • nullptr是空指针常量,可以隐式转换成任意指针类型,但不会自动转换为整数类型;而NULL是宏,整数类型,【注意】 可能会导致类型安全问题,如下。
void f(int a) {cout << "parameter int" << endl;}

void f(void* a) { cout << "parameter void*" << endl;}

int main() {
    f(NULL); //调用f(int)
    f(nullptr); //调用f(void*)
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux初识

1.操作系统的那点事 &#xff08;1&#xff09;结论&#xff1a;操作系统是作软硬件管理的软件&#xff1b; &#xff08;2&#xff09;计算机是操作系统&#xff0c;设备驱动&#xff0c;硬件三个相互结合发挥作用的&#xff0c;操作系统是用来管理硬件的&#xff0c;常见的…

【Linux-I.MX6ULL裸机学习】中断向量表

代码来自于正点原子阿尔法Linux开发板光盘 比如在中断向量表中规定了&#xff1a;在某个地址0x80000A对应着某个中断服务函数&#xff0c;那么在产生这个中断时&#xff0c;就会从0x80000A这个地址去读取中断服务函数&#xff0c;并执行。 如果想改变这个地址&#xff0c;也就是…

【Linux】基础命令

常用命令及参数&#xff1a;dir表示文件夹&#xff0c;file表示文件&#xff08;file可表示其他目录下的文件&#xff09; pwd命令&#xff1b;查看当前所属文件夹&#xff08;print working directory&#xff09; ls [选项] dir&#xff1b;查看当前、指定文件夹目录内容&am…

《Fundamentals of Power Electronics》——隔离型CUK转换器、

以下是隔离型CUK转换器的相关知识点&#xff1a; Cuk电路的隔离型版本获得方式不同。基础非隔离型Cuk电路如下图所示。 将上图中电容C1分成两个串联的电容C1a和C1b&#xff0c;得到结果如下图所示。 在两个电容之间插入一个变压器&#xff0c;得到如下图所示电路。 变压器极性…

Quora 首席执行官亚当·德安杰洛 (Adam D’Angelo) 谈论了 AI、聊天机器人平台 Poe,以及 OpenAI 为什么不是竞争对手

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽

进程间为何要通讯 ? 鸿蒙内核默认支持 64个进程和128个任务&#xff0c;由进程池和任务池统一管理.内核设计尽量不去打扰它们&#xff0c;让各自过好各自的日子&#xff0c; 但大家毕竟在一口锅里吃饭&#xff0c; 不可能不与外界联系&#xff0c; 联系就得有渠道&#xff0c…

虚幻引擎笔记

虚幻引擎笔记 一、蓝图类二、创建自定义Character蓝图三、操作映射和轴映射 一、蓝图类 Actor&#xff1a;可以放置在关卡中的物体Pawn&#xff1a;相当于游戏角色&#xff0c;可以通过玩家控制器来控制角色&#xff1a;在Pawn的基础上增加了四处走动的功能。创建游戏角色时使用…

创意无限,批量剪辑技巧:视频剪辑中的画中画技巧大揭秘

在视频剪辑的世界里&#xff0c;创意是无限的&#xff0c;而技巧则是实现这些创意的关键。画中画技巧作为视频剪辑中的一种高级技术&#xff0c;可以带给观众新颖的视觉体验&#xff0c;提升视频的质量和观赏性。本文将深入探讨批量剪辑中的画中画技巧&#xff0c;揭示其背后的…

就业班 第三阶段(redis) 2401--5.7 day2 redis2 哨兵(前提是做好了主从)+redis集群

1、设置密码&#xff08;redis&#xff09; 先在redis.conf里面找到这个 后面写上要设置的密码即可 2、哨兵模式 监控redis集群中master状态的的工具 在做了主从的前提下 主 从1 从2 作用 1)&#xff1a;Master状态检测 2)&#xff1a;如果Master异常&#xff0c;则会进行…

2-5 任务:打印九九表

本次实战的目标是通过编写程序实现打印九九乘法表、字符矩形、字符平行四边形和字符菱形等图形&#xff0c;以及解决百钱买百鸡问题和输出素数等实际问题。在实战过程中&#xff0c;我们将学习并掌握以下知识点。 双重循环的使用&#xff1a;通过双重循环实现九九乘法表的打印&…

告别杂乱桌面,开启纯净视界!DeskCover Pro,Mac用户的桌面神器!

DeskCover Pro for Mac是一款专为macOS设计的桌面图标隐藏软件&#xff0c;其主要功能和特点包括&#xff1a; 桌面图标隐藏&#xff1a;通过单击鼠标或按全局热键&#xff0c;可以快速隐藏桌面上的所有图标&#xff0c;为您提供一个干净整洁的工作环境。窗口聚焦&#xff1a;…

证券基金信创联盟研讨会:YashanDB分享金融核心数据库技术实践

4月26日&#xff0c;由证券基金行业信息技术应用创新联盟主办、WG3稽核风控系统工作组承办、国信证券股份有限公司协办的信创联盟2024年度系列研讨会第三期-稽核风控系统信创实践成功举办。国内头部企业国信证券、申万宏源证券、信达证券、国金证券、广发证券等单位共计300余人…

【数据结构】链表经典OJ题目练习(2)

面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;先计算出链表的长度&#xff0c;在将链表中的值存在数组中&#xff0c;在返回第k个节点。 思路2&#xff1a;利用快慢指针&#xff0c;先让快指针走k步&#xff0c;在让快慢指针分…

[译]Elasticsearch _source Doc_values And Store Performance

原文地址 https://sease.io/2021/02/field-retrieval-performance-in-elasticsearch.html 在这篇博文中&#xff0c;我想从性能的角度探讨 Elasticsearch 为我们存储字段和查询时检索字段提供了哪些可能性。 事实上&#xff0c;Lucene&#xff08;Elasticsearch 和 Solr 构建的…

详细分析Mybatis与MybatisPlus中分页查询的差异(附Demo)

目录 前言1. Mybatis2. MybatisPlus3. 实战 前言 更多的知识点推荐阅读&#xff1a; 【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09;java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09; 本章节主要以Demo为例&#xff…

122. Kafka问题与解决实践

文章目录 前言顺序问题1. 为什么要保证消息的顺序&#xff1f;2.如何保证消息顺序&#xff1f;3.出现意外4.解决过程 消息积压1. 消息体过大2. 路由规则不合理3. 批量操作引起的连锁反应4. 表过大 主键冲突数据库主从延迟重复消费多环境消费问题后记 前言 假如有家公司是做餐饮…

3行代码,实现一个取色器

前言 今天发现了一个很好玩的 API ——EyeDropper。 EyeDropper API 提供了一种创建拾色器工具的机制。使用该工具,用户可以从屏幕上取样颜色,包括浏览器窗口之外的区域。 这是 MDN 上对它的介绍,可以取包括浏览器窗口之外的区域。我们一起看看是怎么个事 什么是取色器 取…

24年最新AI数字人简单混剪

24年最新AI数字人简单混剪 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码&#xff1a;0b8x

【C 数据结构-图】2. 图的存储结构

文章目录 【 1. 图的顺序存储结构 】1.1 基本原理1.2 顺序存储结构的 C 实现 【 2. 图的链式存储结构 】2.1 图的临接表存储结构2.1.1 临接表的 基本原理2.1.2 临接表的 链表节点2.1.3 邻接表 各结构体的C实现2.1.4 临接表 计算顶点的出度和入度邻接表计算 无向图的出度和入度邻…

【Fastadmin】后台角色组权限问题(multi,开关switch,控制器新增方法)

1.列表开关类型的权限 如图&#xff1a; 此类开关请求的方法为multi 开关在点击的时候默认是只允许修改数据库的status字段的&#xff0c;如果我们开关不是status字段&#xff0c;我们需要在服务端对应的控制器中定义protected $multiFields"id,name,swith";&#x…