C++面经
文章平均质量分 89
C++面经
liufeng2023
日拱一卒
展开
-
462-百度面经2
哈希表 红黑树!栈的应用:队列的引用:线性表 排序算法 哈希表 二叉树 五大算法BST树:BST树的第K大的节点:求中序遍历第K大的节点即可!size:得到元素的个数;compacity:容量大小;可以构造一个函数,不断的向vector中插入元素,打印size大小和compacity大小,即可知道是怎么扩容的!(Win是1.5倍扩容,GCC下是2倍扩容!)为什么是2倍扩容?为什么1.5倍扩容最好?2倍扩容:1.5倍扩容:关联容器:set和map:红黑树;unordered_set和unordered_ma原创 2022-07-07 18:48:51 · 685 阅读 · 0 评论 -
454-百度面经1
项目:介绍项目:面试官说:你写的项目没有必要啊?项目中遇到了哪些问题?项目如何保证一件事情是否完成?三种情况;项目中怎样实现高并发的?TCP保证发送数据不丢且不重?应用保证发送数据不丢且不重?面试的时候聊到TCP协议和UDP协议,面试官经常给你一种场景让你设计;TCP的三次握手和四次挥手!不进行动态扩容的话,线程池就是死的,数量固定好不好?客观的看!不进行动态扩容:进行动态扩容:线程开销:解决方法:从swap函数引入,形参想要改变实参的值,使用值传递不行;C语言中使用指针,C++中使用引用!在windows原创 2022-07-06 14:33:41 · 971 阅读 · 0 评论 -
450-深信服面经1
注意:函数和变量前面加extern关键字的区别:动态链接库DLL库中加extern “C”的作用:什么是内存对齐?內存对齐系数:内存对齐规则:1、结构体第一个数据成员放在偏移量offset为0的地方,以后每个数据成员的对齐按照 #pragma pack指定的数值 和 这个数据成员自身长度中,比较小的进行对齐(到首地址的偏移量,指定的数值需要是这个小的数的倍数)。2、在数据成员完成各自对齐之后,类(结构或联合)本身也要进行对齐,对齐将按照 #pragma pack指定的数值 和 结构(或联合)最大数据成员长度原创 2022-07-02 11:58:16 · 323 阅读 · 0 评论 -
447-哔哩哔哩面经1
const:volatile:不对变量加volatile,编译器会对变量做一些优化:而加了volatile修饰,生成的汇编是这样:C++的volatile一般只会用在与硬件通信,平时我们编程几乎用不到。具体可以看:https://en.cppreference.com/w/cpp/language/cv四个过程!1、预处理;主要做了以下工作:2、编译;把预处理后的文件进行一系列操作生成相应的汇编文件3、汇编;4、链接;想更深入了解的朋友,建议看看《程序员的自我修养》,也可以看看我的总结篇:https原创 2022-07-01 20:23:31 · 282 阅读 · 0 评论 -
448-Linux生成可执行程序的过程
你知道一次gcc命令究竟经历了什么吗?我们先来看一段C语言示例源代码:编译运行:如图一:我们平时都会使用gcc来编译程序,这一行简单的命令其实经历了很多复杂的过程:首先使用file看一下test.cc文件类型:我们接下来看看这每个过程都做了什么?命令:再看下test.i的文件类型:这里可以看出预处理后的文件和预处理前的文件类型是相同的,都是文本文件,也可以直接查看test.i的内容,里面代码较多,就不贴上来了。预处理主要操作有这几个:命令:再查看文件类型:如图二,编译过程就是把预处理后原创 2022-07-01 20:06:05 · 99 阅读 · 0 评论 -
444-C++基础语法(131-136)
背景:但是下面几种情形是不可以这么使用的:以下是一个 hello.c 程序:在 Unix 系统上,由编译器把源文件转换为目标文件。这个过程大致如下:预处理阶段: 处理以 # 开头的预处理命令;编译阶段: 翻译成汇编文件;汇编阶段: 将汇编文件翻译成可重定位目标文件;链接阶段: 将可重定位目标文件和 printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件。静态链接:链接器主要完成以下两个任务:目标文件:动态链接静态库有以下两个问题:共享库是为了解决静态库的这两个问题而设计原创 2022-06-30 20:28:07 · 148 阅读 · 0 评论 -
443-C++基础语法(121-130)
对比值传递,引用传参的好处:值传递:用引用作为返回值最大的好处就是在内存中不产生被返回值的副本。但是有以下的限制:1、操作对象不同2、执行效率不同3、实现功能不同1、传递引用给函数与传递指针的效果是一样的。2、使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;3、使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;指针传参在主调函数的调用点处,必须用变量的地址原创 2022-06-30 18:53:20 · 153 阅读 · 0 评论 -
442-C++基础语法(111-120)
参数的含义是:volatile用在如下的几个地方:114、C++中标准库是什么?C++ 标准库可以分为两部分:1、标准函数库: 这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承自 C 语言。2、面向对象类库: 这个库是类及其相关函数的集合。1、string 是c++标准库里面其中一个,封装了对字符串的操作,实际操作过程我们可以用const char*给string类初始化。三者的转化关系如下所示:1、string转const char*2、const char * 转string,直接赋原创 2022-06-30 16:26:35 · 258 阅读 · 0 评论 -
441-C++基础语法(101-110)
区别:只能重载已有的运算符,而无权发明新的运算符;对于一个重载的运算符,其优先级和结合律与内置类型一致才可以;不能改变运算符操作数个数;两种重载方式:成员运算符重载和非成员运算符重载,成员运算符比非成员运算符少一个参数;下标运算符、箭头运算符必须是成员运算符重载;引入运算符重载,是为了实现类的多态性;当重载的运算符是成员函数时,this绑定到左侧运算符对象。成员运算符函数的参数数量比运算符对象的数量少一个;至少含有一个类类型的参数;下标运算符必须是成员函数,下标运算符通常以所访问元素的引用原创 2022-06-30 14:45:48 · 298 阅读 · 0 评论 -
440-C++基础语法(91-100)
值传递: 是最普通的传递方式,如函数定义为fun(int a),在调用的地方有int x= 1,使用fun(x)即可。这种方式在fun(int a)函数内部的对a的修改不能导致外部x的变化。指针传递: 是地址传递,函数定义为fun(int *a),形参为指针,要求调用的时候传递进去一个参数的地址,例如int x = 1; fun(&x)。这种方式在fun(int *a)函数内部的对a的修改能导致外部x的变化。引用传递: 只有C++支持,引用传递函数定义为fun(int &a),这里&符号是引用而不是取地址的原创 2022-06-30 10:54:25 · 273 阅读 · 0 评论 -
439-C++基础语法(81-90)
避免内存泄露的几种方式:检测工具:成员初始化列表的概念效率:用初始化列表会快一些!原因:举个例子:从代码运行结果可以看出,在构造函数体内部初始化的对象b多了一次构造函数的调用过程,而对象a则没有。由于对象成员变量的初始化动作发生在进入构造函数之前,对于内置类型没什么影响;但如果有些成员是类,那么在进入构造函数之前,会先调用一次默认构造函数,进入构造函数后所做的事其实是一次赋值操作(对象已存在),所以如果是在构造函数体内进行赋值的话,等于是一次默认构造加一次赋值;而初始化列表只做一次赋值操作。8原创 2022-06-29 23:39:31 · 223 阅读 · 0 评论 -
436-C++基础语法(71-80)
C和C++中静态局部变量的初始化节点又有点不太一样:x的地址为ebp-4,b的地址为ebp-8,因为栈内的变量内存是从高往低进行分配的,所以b的地址比x的低。lea eax,[ebp-4] 这条语句将x的地址ebp-4放入eax寄存器。mov dword ptr [ebp-8],eax 这条语句将eax的值放入b的地址。ebp-8中上面两条汇编的作用即:将x的地址存入变量b中,这不和将某个变量的地址存入指针变量是一样的吗?所以从汇编层次来看,的确引用是通过指针来实现的。new:new简单类型直接调用ope原创 2022-06-29 20:27:49 · 256 阅读 · 0 评论 -
435-C++基础语法(61-70)
浅拷贝:深拷贝:从执行结果可以看出,浅拷贝在对象的拷贝创建时存在风险,即被拷贝的对象析构释放资源之后,拷贝对象析构时会再次释放一个已经释放的资源,深拷贝的结果是两个对象之间没有任何关系,各自成员地址不同。内联函数适用场景:1、public,protected和private访问:访问权限:派生类可以继承基类中除了构造/析构、赋值运算符重载函数之外的成员,但是这些成员的访问属性在派生过程中也是可以调整的。三种派生方式的访问权限如下表所示:(注意外部访问并不是真正的外部访问,而是在通过派生类的对象对基类成员的原创 2022-06-29 10:56:02 · 262 阅读 · 0 评论 -
433-C++基础语法(51-60)
用户告诉操作系统执行HelloWorld程序(通过键盘输入等)操作系统:找到helloworld程序的相关信息,检查其类型是否是可执行文件;并通过程序首部信息,确定代码和数据在可执行文件中的位置并计算出对应的磁盘块地址。操作系统:创建一个新进程,将HelloWorld可执行文件映射到该进程结构,表示由该进程执行helloworld程序。操作系统:为helloworld程序设置cpu上下文环境,并跳到程序开始处。执行helloworld程序的第一条指令,发生缺页异常操作系统:分配一页物理内存,并将代码从磁盘读原创 2022-06-28 17:28:48 · 311 阅读 · 0 评论 -
432-C++基础语法(41-50)
default关键字可以显式要求编译器生成合成构造函数,防止在调用时相关构造函数类型没有定义而报错。如果没有加语句1,语句2会报错,表示找不到参数为空的构造函数,将其设置为default可以解决这个问题。delete关键字可以删除构造函数、赋值运算符函数等,这样在使用的时候会得到友善的提示。在执行语句1时,会提示new方法已经被删除,如果将new设置为私有方法,则会报惨不忍睹的错误,因此使用delete关键字可以更加人性化的删除一些默认方法。构造函数拷贝构造函数赋值运算符44、拷贝构造函数和赋值运算符原创 2022-06-28 15:49:17 · 210 阅读 · 0 评论 -
431-C++基础语法(31-40)
C++的多态性:例子: Base为基类,其中的函数为虚函数。子类1继承并重写了基类的函数,子类2继承基类但没有重写基类的函数,从结果分析子类体现了多态性,那么为什么会出现多态性,其底层的原理是什么?虚表和虚基表指针的概念:上图中展示了虚表和虚表指针在基类对象和派生类对象中的模型,下面阐述实现多态的过程:这样指向派生类的基类指针在运行时,就可以根据派生类对虚函数重写情况动态的进行调用,从而实现多态性。析构函数:构造函数:首先整理一下虚函数表的特征:根据以上特征,虚函数表类似于类中静态成员变量,静态成员变量也原创 2022-06-28 09:58:00 · 198 阅读 · 0 评论 -
410-C++之STL模板库(9-11)
则是一种双向开口的连续线性空间。deque由一段一段的定量连续空间组成,一旦需要增加新的空间,只要配置一段定量连续空间拼接在头部或尾部即可,因此deque的最大任务是如何维护这个整体的连续性deque的数据结构如下:deque内部有一个指针指向map,map是一小块连续空间,其中的每个元素称为一个节点,node,每个node都是一个指针,指向另一段较大的连续空间,称为缓冲区,这里就是deque中实际存放数据的区域,默认大小512bytes。整体结构如上图所示。deque的迭代器数据结构如下:虽然也提供随原创 2022-06-22 23:25:09 · 182 阅读 · 0 评论 -
404-C++之STL模板库(1-8)
C++ STL从广义来讲包括了三类:算法,容器和迭代器。智能指针(std::shared_ptr和std::unique_ptr)即RAII最具代表的实现,使用智能指针,可以实现自动的内存管理,再也不需要担心忘记delete造成的内存泄漏。毫不夸张的来讲,有了智能指针,代码中几乎不需要再出现delete了。++it好!1、前置返回一个引用,后置返回一个对象;2、前置不会产生临时对象,后置必须产生临时对象,临时对象会导致效率降低。4、STL中hashtable的实现?STL中的hashtable使用的是原创 2022-06-21 20:30:10 · 308 阅读 · 0 评论 -
403-C++内存管理(11-14)
编译器会给空类隐含加上一个字节,这样空类实例化之后就会拥有独一无二的内存地址。当该空白类作为基类时,该类的大小就优化为0了,子类的大小就是子类本身的大小。这就是所谓的空白基类最优化。因为有虚函数的类对象中都有一个虚函数表指针 __vptr,其大小是4字节静态成员存放在静态存储区,不占用类的大小, 普通函数也不占用类大小。静态成员a不占用类的大小,所以类的大小就是b变量的大小 即4个字节。this指针首先入栈,然后成员函数的参数从右向左进行入栈,最后函数返回地址入栈。.........原创 2022-06-21 17:27:30 · 163 阅读 · 0 评论 -
396-C++内存管理(1-10)
空类(无非静态数据成员)的对象的size为1, 当作为基类时, size为0。C++中的内存分区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区和代码区。如下图所示:栈: 在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限堆: 就是那些由 new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个 delete。如果程序员没有释放掉,那么在程序结束后原创 2022-06-19 21:34:24 · 155 阅读 · 0 评论 -
395-C++基础语法(21-30)
编译阶段:安全性:内存占用:不考虑类的情况:考虑类的情况:不考虑类的情况:考虑类的情况:当在父类中使用了虚函数时候,你可能需要在某个子类中对这个虚函数进行重写,以下方法都可以:如果不使用override,当你手一抖,将**foo()写成了f00()**会怎么样呢?所以,override的作用就出来了,它指定了子类的这个虚函数是重写的父类的,如果你名字不小心打错了的话,编译器是不会编译通过的!2、final当不希望某个类被继承,或不希望某个虚函数被重写,可以在类名和虚函数后添加final关键字,添加fi原创 2022-06-19 20:01:08 · 153 阅读 · 0 评论 -
373-C++基础语法(11-20)
在32位环境下,指针占用大小为4字节。而在64位的编译环境下的,指针的占用大小为8字节;假设数组其中:相同点不同点ASCII 码:一个英文字母(不分大小写)为一个字节,一个中文汉字为两个字节。UTF-8 编码中,一个英文字为一个字节,一个中文为三个字节。Unicode 编码中,一个英文为一个字节,一个中文为两个字节。......原创 2022-06-15 19:56:32 · 166 阅读 · 0 评论 -
368-C++基础语法(1-10)
全局对象的析构函数;调用atexit注册的函数,然后结束进程。attribute((destructor))—利用attribute关键字定义destructorc++11以后引入两个关键字 alignas与 alignof。alignof:可以计算出类型的对齐方式;alignas:可以指定结构体的对齐方式。指针是一个变量,存储的是一个地址,引用跟原来的变量实质上是同一个东西,是原变量的别名;指针可以有多级,引用只有一级;指针可以为空,引用不能为NULL,且在定义时必须初始化;指针在初始化后可以改变指向,而原创 2022-06-14 21:25:50 · 285 阅读 · 0 评论 -
335-面经7
map底层实现: 红黑树怎么定位内存泄漏的问题,通过工具进行检测,比如说在VS上,通过添加vld,在运行的过程检查可能出现内存泄漏的问题,会指到相应的代码上。为了防止内存泄漏,我们做好使用智能指针来智能管理资源。SGI STL二级空间配置器的内存池的实现就可以了!!!(类似于哈希表)stack和queue的底层实现:stack和queue是容器适配器;底层没有实现任何数据结构,底层直接依赖一个现有的顺序容器,依赖的是deque,第二维数组独立new出来,不需要连续,内存碎片比较多的情况下内存分配是容易成功的原创 2022-06-08 11:15:19 · 94 阅读 · 0 评论 -
334-面经6
deque底层是动态开辟的二维数组定义的2个宏:(不同的VS,g++,都有更改值)#define MAP_SIZE 2#define QUE_SIZE(T) 4096/sizeof(T)一维数组的初始大小 MAP_SIZE (T*)第二维数组默认开辟的大小就是QUE_SIZE(int) 1024deque是双端队列 两端都有队头和队尾 两端都可以插入删除时间复杂度是O(1)当第一维所有的位置都开辟了第二维,再增加元素的话就要扩容扩容: 把第一维数组按照2倍的方式进行扩容 2-4-8-16。。。扩原创 2022-06-08 10:20:30 · 87 阅读 · 0 评论 -
333-面经5
宏是,内联是宏是预编译阶段(字符串替换) 处理的(不仅仅可以表示一个常量,一个表达式,一组代码,一个函数)内联是编译阶段(在函数调用点,通过函数的实参把函数代码直接展开调用,节省了函数的调用开销)处理的(只是修饰函数的)对于调试,宏是没有办法调试的, inline函数可以调试(debug版本下inline就和普通函数一样,有标准的函数调用过程)#define 可以定义常量,代码块,函数块 缺点是不好维护 而且宏定义代码多了,每一行后面要加个斜杆,而且斜杆后面是不能空格的。inline只是修饰函数在栈stac原创 2022-06-07 21:38:50 · 84 阅读 · 0 评论 -
332-面经4
4、vector和数组的区别,STL的容器分类,各容器底层实现?直接使用数组, 数组的内存够不够用,是不是需要扩容?需要扩容代码怎么写?会和业务代码混杂一块。vector是数组的一个面向对象的表示,把数组封装起来了。自动扩容,添加,删除,不用担心数组的内存和空间越界。vector: 可扩容的数组deque:动态开辟第二维的数组list :双向循环链表stack(依赖deque适配):容器适配器,没有自己的数据结构和迭代器push pop queue(依赖deque的方法)priority_q原创 2022-06-07 20:11:33 · 89 阅读 · 0 评论 -
331-面经3
因为C和C++生成符号的方式不同,所以C和C++语言之间的API接口是无法直接调用的。怎么办?C语言的函数声明必须扩在__cpluscplus宏的作用是: C++编译器内置了这个宏,如果是C语言编译器来编译这个代码,没有这个宏,就直接使用C接口就可以了,如果是C++环境,因为有这个宏,extern C就会展开,告诉C++编译器这个函数sum是在C语言下生成的,调用它的话按照C语言的符号规则来去找它。按照C语言的符号规则就是sum,按照C++语言的符号规则就是sum_int_int。从本质上来说,访问越界就原创 2022-06-07 19:21:21 · 146 阅读 · 0 评论 -
269-面经2
1、C++this指针干什么用的?1个类型定义的对象都有各自的成员变量,但是是共享一套成员方法,在成员方法里,具体访问谁的成员变量,这个是靠this指针区分的。1个类型定义了很多对象,都是私有的成员变量,但是共享一套成员方法,在成员方法里面访问谁的成员变量?通过this指针区分。C++的类的普通成员方法在被编译的时候都会多出来一个this指针。2、C++的new和delete,什么时候用new[]申请,可以用delete释放?new和delete本质上是一个运算符重载。operator .原创 2022-05-22 16:01:22 · 150 阅读 · 0 评论 -
263-面经1(商汤C++机器学习)
1、程序的内存布局程序运行时叫进程就是进程的虚拟地址空间这张图是32位x86体系下的进程的虚拟地址空间,下面是低地址,上面是高地址。我们从最下面(低地址开始看)往上看:从0-0x08048000是0地址,然后从0x08048000往上,放的是代码段(.text段:指令,只读不能写);数据存储的.Data和.BSS段(没有初始化/初始化为0)然后是堆Heap(malloc,new)然后是Memory Mapping Segment共享库(printf,scanf这类要包含头文件的函数,比如原创 2022-05-21 21:48:42 · 260 阅读 · 0 评论