面试经验
c/c++
1、malloc与new的区别
1、new是操作符,malloc是函数
2、new使用时先分配内存,再调用构造函数,释放时调用析构函数
3、new只能分配实例所占类型的整数倍,malloc可以随意分配。
4、new失败返回异常,malloc返回NULL
2、C语言内存分配的方式
1、静态区分配:编译时分配好,主要储存全局变量,static变量等。
2、栈分配:执行函数时,函数内部的局部变量,函数结束时,这些储存单元自动被释放
3、堆分配:也叫动态分配,通过malloc以及NEW来分配,程序员自己负责free或者delete自己申请的内存
3、struct 与 class的区别
1、class可以继承,类,接口,struct只能继承接口
2、class有默认的无参构造函数,struct没有,而且struct没有析构函数
3、class有继承级别,protected等等
4、class用垃圾回收机制保证内存的回收,struct使用完之后自动接触内存分配。
4、const常量和#define的区别
1、前者在编译期起作用,后者在预处理和编译期起作用
2、前者没有数据类型,只是简单的替换,后者有数据类型,可以进行判断,避免基础的错误。
3、前者只有一个备份,后者替换多少次就有多少个备份。
5、vector与list
1、vector 内存空间连续,底层是数组,list内存空间不连续,是双向链表,都是在堆中分配
2、vector随机访问效率高,在非尾部插入困难,list相反
3、迭代器支持不同,vector支持的“+”等等,list不支持
6、各个stl的底层实现
1、vector 为数组,支持快速随机访问
2、list底层为 双向链表,支持快速增删
3、deque是中央控制器和多个缓冲区
4、stack底层一般用list和deque实现
5、queue一般使用list和deque实现,封闭头部
6、priority_queue使用vector为底层容器,使用heap来管理规则
7、set底层为红黑树,有序不重复 multiset可重复
8、map底层为红黑树,有序不重复 multimap可重复
9、hash_set底层为hash表,无序不重复
10、hash_map底层为hash表 无序不重复
7、动态绑定与静态绑定
1、动态绑定就是继承虚函数
2、静态绑定就是函数重载
8、多态实现的三个条件、实现的原理
条件:有继承、有虚函数(virtual)重写、有父类指针(引用)指向子类对象。
实现原理:当类中声明虚函数时,编译器会在类中生成一个 虚函数表;虚函数表是一个储存 类成员函数指针的数据结构;virtual成员函数会被编译器放入虚函数表中。存在虚函数时,在创建的每个对象中都有一个指向虚函数表的指针(vptr指针)函数在运行的时候会重写这个虚函数。
9、析构函数一般写成虚函数的原因
由于类的多态性,基类指针可以指向派生类的对象。如果删除该基类的指针,就会调用该指针指向的派生类的析构函数,而派生类的析构函数又会自动调用基类的析构函数,这样整个派生类的对象被完全释放。
10、构造函数不能是虚函数的原因
虚函数相应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。
11、抽象类与纯虚函数
-
纯虚函数: 一个函数只有函数名和形参列表,没有具体实现;语法:virtual double GetArea()=0;
-
抽象类: 在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象。抽象类是不完整的,它只能用作基类。
12、重载、覆盖
重载是参数类型或者个数不同,覆盖是子类重写父类函数。
13、栈和队列
1、规则:栈先入后出,队列先入先出
2、插入删除定义不同:栈只能在一端插入和删除,队列只能在一端插入另一端删除
14、strcpy和memcpy的区别
(1)复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
(2)复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
(3)用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。
15、了解智能指针吗?
主要4个,auto_ptr(C++ 98)、unique_ptr、shared_ptr 和weak_ptr(C++ 11)
auto_ptr :现在用的少,老版C++用,能自动释放。
unique_ptr: 两个unique_ptr 不能指向一个对象,即 unique_ptr 不共享它所管理的对象,并可以放在容器中。
shared_ptr:shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象,shared_ptr 利用引用计数的方式实现了对所管理的对象的所有权的分享,即允许多个 shared_ptr 共同管理同一个对象。比较麻烦,需要自己写辅助类。
weak_ptr: weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能指针。
16、lambda函数
模板:capture mutable ->return-type{statement}
1.[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
2.(parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;
3.mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);
4.->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;
5.{statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:
1.[var]表示值传递方式捕捉变量var;
2.[=]表示值传递方式捕捉所有父作用域的变量(包括this);
3.[&var]表示引用传递捕捉变量var;
4.[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
5.[this]表示值传递方式捕捉当前的this指针。
上面提到了一个父作用域,也就是包含Lambda函数的语句块,说通俗点就是包含Lambda的“{}”代码块。上面的捕捉列表还可以进行组合,例如:
1.[=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
2.[&,a,this]表示以值传递的方式捕捉变量a和this,引用传递方式捕捉其它所有变量。
不过值得注意的是,捕捉列表不允许变量重复传递。下面一些例子就是典型的重复,会导致编译时期的错误。例如:
3.[=,a]这里已经以值传递方式捕捉了所有变量,但是重复捕捉a了,会报错的;
4.[&,&this]这里&已经以引用传递方式捕捉了所有变量,再捕捉this也是一种重复。
17、说说C++的模板
18、未初始化的全局变量和局部变量值是什么?
全局变量为0,局部变量栈上分配为随机数。
局部变量为随机数的主要原因是因为局部变量是栈上分配的,栈内存是反复使用的,如果不进行初始化就是上一次写入的值。
19、说说友元类,是否是相互的,是否能被继承
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
20、说说你用的C++版本,C++11有什么新特性?
1、auto变量类型自动推导
2、基于范围的for循环 for(int a:vec)
3、智能指针
4、stl 新增unordered 哈希表map
5、lambda函数:无名函数,用在sort中比较多
6、线程库
21、如何防止Double Free
先判断一波
if§
{
free§;
}
或者每次free之后把指针指向NULL;
22、(IO多路复用)select、poll、epoll区别和实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fDi7ZUeD-1669710834043)(https://vipkshttps15.wiz.cn/editor/82363800-126d-11ed-92fe-017f9d161f3f/11473e42-1881-475e-85cf-79bc99be3c2c/resources/EHIUFSNFwA9sBM4qqITFkhp0TumlIX7TkpG5Wn_p18E.png?token=W.no8iG4jpkwK46lJ5WxRJFF3UqKkka8sbsTM-36WRMKzM4sYCR5IxYQXmlm_YStU)]
实现见 socket IO复用
select:
优点:所有平台都支持,良好的跨平台支持也是一个优点
缺点:文章来源地址https://www.toymoban.com/news/detail-581151.html
1、数量限制,Linux平台一般是1024个
2、线性扫描,采用轮询的方法,效率较低
3、select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理,因此需要维护一个用来存放大量fd的数据结构(fd_set)fd_set简单地理解为一个长度是1024的比特位,每个比特位表示一个需要处理的FD,如果是1,那么表示这个FD有需要处理的I/O事件,否则没有,其是连续存储的。每次select查询都要遍历整个事件列表。
poll:
主要操作的数据结构:
struct pollfd {
int fd; // 需要监视的文件描述符
short events; // 需要内核监视的事件
short revents; // 实际发生的事件
};
优点:
1、在使用该结构的时候,不用进行比特位的操作,而是对事件本身进行操作就行。同时还可以自定义事件的类型。这样的好处是在内存中存放就不需要连续的内存地址,很像是list队列结构,读或者写事件数量(文件描述符数量)理论上是无限的,取决于内存的大小。
2、它没有最大连接数的限制,原因是它是基于链表来存储的。文章来源:https://www.toymoban.com/news/detail-581151.html
缺点:
- 内核需要将消息传递到用户空间,都需要内核拷贝动作。需要维护一个用来存放大量fd的数据结构,使得用户空间和内核空间在传递该结构时复制开销大。大量的fd被整体复制于用户态和内核地址空间之间,而
到了这里,关于嵌入式面试常考问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!