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; //局部constint* 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;
}

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

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

相关文章

JAVA面试常见面试问题01

1、队列系列 1.1、选型 ActiveMq ⼩规模场景&#xff0c;有较低概率丢失消息&#xff0c;官方社区维护少 RabbitMq ⼩规模场景&#xff0c;吞吐量⽐较低&#xff0c;消息积累会严重影响性能 RocketMQ ⼩规模场景&#xff0c;官⽅⽂档和周边⽣态还不够成熟 Kafka 大规模场景…

STM32——基础篇

技术笔记&#xff01; 一、初识STM32 1.1 ARM内核系列 A 系列&#xff1a;Application缩写。高性能应用&#xff0c;比如&#xff1a;手机、电脑、电视等。 R 系列&#xff1a;Real-time缩写。实时性强&#xff0c;汽车电子、军工、无线基带等。 M 系列&#xff1a;Microcont…

MCU做死循环时,到底应该用for(;;) 还是wihile(1)

MCU做死循环时 for while stm32中老工程师用forfor while背景for版本while版本正方观点&#xff1a;哪有好的编译器&#xff1a;反方观点&#xff1a;这种代码过时了工程师实地测试&#xff1a;和编译器和优化有关 建议还是用for参考 stm32中老工程师用for /* Start scheduler …

linux中相关压缩文件的便捷方式

1.压缩解压缩命令 tar命令 tar命令位于/bin目录下&#xff0c;它能够将用户所指定的文件或目录打包成一个文件&#xff0c;但不做压缩。 一般Linux上常用的压缩方式是选用tar将许多文件打包成一个文件&#xff0c;再以gzip压缩命令压缩成xxx.tar.gz(或称为xxx.tgz)的文件 常…

MATLAB函数fir1的C语言移值

要移值的matlab函数: h3 = fir1(16,[0.25 0.50]); C语言版本 #include <iostream> #include <cmath>#define PI acos(-1)double sincEasy(double *x, int len, int index) {double temp = PI * x[index];if (temp == 0) {return 1.0; // sinc(0) = 1}return s…

【前端】HTML基础(1)

文章目录 前言一、什么是前端二、HTML基础1、 HTML结构1.1 什么是HTML页面1.2 认识HTML标签1.3 HTML文件基本结构1.3 标签层次结构1.4 创建html文件1.5 快速生成代码框架 三、Emmet快捷键 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及…

华为机考入门python3--(23)牛客23- 删除字符串中出现次数最少的字符

分类&#xff1a;字符串 知识点&#xff1a; 访问字典中keychar的值&#xff0c;不存在则返回0 my_dict.get(char, 0) 字典的所有值 my_dict.value() 列表中的最小值 min(my_list) 题目来自【牛客】 import sysdef delete_min_freq_char(s):# 计算字母出现的频次…

【linux】dmesg工具

dmesg介绍 dmesg工具用途&#xff1a; dmesg - print or control the kernel ring buffer kernel ring buffer, 内核环形缓冲区&#xff0c;也叫环形队列&#xff0c;Linux内核日志就存储在一个环形队列中&#xff0c;环形队列满的时候&#xff0c;新的消息会覆盖掉旧的消息。…

《十八》QThread多线程组件

本章将重点介绍如何运用QThread组件实现多线程功能。 多线程技术在程序开发中尤为常用&#xff0c;Qt框架中提供了QThread库来实现多线程功能。当你需要使用QThread时&#xff0c;需包含QThread模块&#xff0c;以下是QThread类的一些主要成员函数和槽函数。 成员函数/槽函数 …

02-Fortran基础--Fortran操作符与控制结构

02-Fortran基础--Fortran操作符与控制结构 0 引言1 操作符1.1 数学运算符1.2 逻辑运算符1.3 关系运算符 2 控制流程2.1 条件结构2.2 循环结构2.3 分支结构 0 引言 运算符和控制流程对编程语言是必须的,Fortran的操作符和控制流程涉及到各种数学运算符、逻辑运算符以及控制结构。…

一文了解栈

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、栈是什么&#xff1f;二、栈的实现思路1.顺序表实现2.单链表实现3.双向链表实现 三、接口函数的实现1.栈的定义2.栈的初始化3.栈的销毁4.入栈5.出栈6.返回栈…

调用nvprof报错: No kernels were profiled. No API activities were profiled.

调用nvprof报错 1 nvprof介绍 nvprof 是 NVIDIA 提供的一款用于分析 CUDA 应用程序性能的命令行性能分析器。CUDA 是一种并行计算平台和编程模型&#xff0c;允许开发人员利用 NVIDIA GPU 进行通用处理。 nvprof 帮助开发人员分析其 CUDA 应用程序的性能&#xff0c;提供各种…

C++继承 - 下

目录 1. 继承和友元 2. 继承与静态成员 3. 菱形继承以及菱形虚拟继承 3.1. 单继承 3.2. 多继承 3.3. 菱形继承 3.4. 菱形虚拟继承 3.5. 菱形继承的底层细节 3.6. 菱形虚拟继承的底层细节 3.7. 虚拟继承 4. 继承的总结 5. 相关继承练习题 5.1. 如何定义一个无法被继…

【Vue3】Ref与Reactive

3.1【ref 创建&#xff1a;基本类型的响应式数据】 作用&#xff1a;定义响应式变量。语法&#xff1a;let xxx ref(初始值)。返回值&#xff1a;一个RefImpl的实例对象&#xff0c;简称ref对象或ref&#xff0c;ref对象的value属性是响应式的。注意点&#xff1a; JS中操作数…

Windows环境编译 VVenC 源码生成 Visual Studio 工程

VVenC介绍 Fraunhofer通用视频编码器(VVenC)的开发是为了提供一种公开可用的、快速和有效的VVC编码器实现。VVenC软件基于VTM&#xff0c;其优化包括软件重新设计以减轻性能瓶颈、广泛的SIMD优化、改进的编码器搜索算法和基本的多线程支持以利用并行。此外&#xff0c;VVenC支…

加索引导致表被锁的原因及处理方法

目录 为什么加索引会导致表被锁&#xff1f;什么情况下会被锁&#xff1f;要注意什么&#xff1f;被锁怎么处理&#xff1f;MySQL查询被锁的表查询被锁的库 PostgreSQL查询被锁的表查询被锁的库 Oracle查询被锁的表查询被锁的库 SQL Server查询被锁的表查询被锁的库 结语 在数据…

Mybatis plus update PG json 类型 报错解决

Mybatis plus update PG json 类型 报错解决 1. 定义的PG数据库对象2. 自定义 JSON Handler3. update Wrapper4. update 报错信息4.1 No hstore extension installed.4.2 Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for …

git commit 提交报错pre-commit hook failed (add --no-verify to bypass) 解决方法,亲测有效

问题截图 今天在执行 git commit 命令时报错&#xff1a;pre-commit hook failed (add --no-verify to bypass) 解决 参考文章&#xff1a;git commit报错&#xff1a;pre-commit hook failed的解决方法 具体原理什么的就不解释了&#xff0c;可以看看上面的参考文章 解决方…

TXT文本高效批量编辑,支持批量将每个单号间的空白行进行删除掉,文本内容管理更方便

TXT文本是一种常用的存储快递单号的数据格式。然而&#xff0c;当TXT文本中存在大量的空白行时&#xff0c;不仅浪费了存储空间&#xff0c;还可能导致批量编辑和查询变得低效。为了解决这一问题&#xff0c;我们推出了高效的TXT文本批量编辑功能&#xff0c;支持批量删除单号间…

PTQ4SAM、Mamba-Attention、AniTalker、IceFormer、U-DiTs、CogDPM

本文首发于公众号&#xff1a;机器感知 PTQ4SAM、Mamba-Attention、AniTalker、IceFormer、U-DiTs、CogDPM PTQ4SAM: Post-Training Quantization for Segment Anything Segment Anything Model (SAM) has achieved impressive performance in many computer vision tasks. Ho…