一些C++开发面试题目

写在最前面

这几个月陆续投了一些公司的C++开发岗,无一例外全挂了,现阶段的知识水平还不足,比如完全不了解数据库方面的知识,也没有什么比较拿得出手的项目等等。这里主要记录一些常见的问题以及答案。比较基础的就不记录了,主要记录一些当时没答上来的。

问题+答案

1.内存对齐的目的以及原理

目的:
1、 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;
某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。因为内存是分块的,假设
每次读取4字节,如果要读取1的内容,需要读两次(0-3+4-8),如果从0开始读,就只需
要一次。
对齐方式:
对于struct(class):对齐方式取编译器的对齐方式和结构体中成员中对齐方式最大的成员
的对齐方式中较小的一个。并且按照变量声明的顺序进行存放。比如char=1,int=4,对于
char+int+char=12,char+char+int=8;一般的编译器默认为8,对于char[33]+int+
double=char[33]+double=48,因为char仍然是1.其中double=8,补充short=2。
对于union:
union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。但是对齐方式会被
改变,比如char[13]+char[12]=13,char[13]+int=16。

2.struct和union区别

union ( 共用体):构造数据类型,也叫联合体 
用途:使几个不同类型的变量共占一段内存(相互覆盖) 
struct ( 结构体 ):是一种构造类 
用途: 把不同的数据组合成一个整体——自定义数据类型

1. struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个
被选中的成员; 而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是
同时存在的,一个struct变量的总长度等于所有成员长度之和,遵从字节对其原则; 在Union中,
所有成员不能同时占用它的内存空间,它们不能同时存在 , Union变量的长度等于最长的成员
的长度。 
2. 对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了,所以,共同体变
量中起作用的成员是最后一次存放的成员; 而对于struct的不同成员赋值是互不影响的。

3.sizeof()的原理

sizeof 不是操纵符,也不是函数,因为在运行阶段没有它,它没有被编译成机器
指令。可以把它看做一个宏。sizeof 在编译期间就处理完成了。

4.为什么说多进程比多线程安全

每个进程会被分配独立的运行空间,所以如果一个进程死亡,别的进程不受影响。多个线程
共享同一个空间,如果一个线程意外死亡,可能会因为占用的内存无法释放产生内存溢出,
或者是因为与其它线程公用的数据没有释放、修改等而是其他的线程发生运行错误。

5.Http和Https的区别

Https:http通信接口部分用ssl/tls协议代替
HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。在数据进行
传输之前,对数据进行加密,然后再发送到服务器。这样,就算数据被第三者所截获,但是由于
数据是加密的,所以你的个人信息让然是安全的。

SL/TLS协议的基本过程是这样的:

1.客户端向服务器端索要并验证公钥。
2.双方协商生成“对话密钥”。
3.双方采用“对话密钥”进行加密通信。

HTTP 有以下安全性问题:
1.	通信使用明文,内容可能会被窃听;
2.	不验证通信方的身份,因此有可能遭遇伪装;
3.	无法证明报文的完整性,所以有可能已遭篡改。

具体过程

1. 客户端发起HTTPS请求
这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。

2. 服务端的配置
采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区
别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请
的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实
就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只
是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东
西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁
起来的东西。

3. 传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

4. 客户端解析证书
这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期
时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问
题,那么就生成一个随即值。然后用证书对该随机值进行加密。就好像上面说的,把随机
值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

5. 传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端
和服务端的通信就可以通过这个随机值来进行加密解密了。

6. 服务段解密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对
称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私
钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪
悍,私钥够复杂,数据就够安全。

7. 传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原

8. 客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程
第三方即使监听到了数据,也束手无策。

6.TCP握手/挥手为什么是3/4次

握手为什么不是2次:
如果仅两次连接可能出现一种情况:客户端发送完连接报文(第一次握手)后由于网络不好,延
时很久后报文到达服务端,服务端接收到报文后向客户端发起连接(第二次握手)。此时客户端
会认定此报文为失效报文,但在两次握手情况下服务端会认为已经建立起了连接,服务端会一直
等待客户端发送数据,但因为客户端会认为服务端第二次握手的回复是对失效请求的回复,不会
去处理。这就造成了服务端一直等待客户端数据的情况,浪费资源。

挥手为什么不是3次:
之所以不是三次而是四次主要是因为被动关闭方将"对主动关闭报文的确认"和"关闭连接"两个操
作分两次进行。对主动关闭报文的确认是为了快速告知主动关闭方,此关闭连接报文已经收到。
此时被动方不立即关闭连接是为了将缓冲中剩下的数据从输出流发回主动关闭方(主动方接收到
数据后同样要进行确认),因此要把"确认关闭"和"关闭连接"分两次进行。

7.HTTP状态码

1XX	Informational(信息性状态码)	接收的请求正在处理
2XX	Success(成功状态码)	请求正常处理完毕
3XX	Redirection(重定向状态码)	需要进行附加操作以完成请求
4XX	Client Error(客户端错误状态码)	服务器无法处理请求
5XX	Server Error(服务器错误状态码)	服务器处理请求出错

8.网络编程的一般步骤

•	TCP:
服务端:socket -> bind -> listen -> accept -> recv/send -> close。
客户端:socket -> connect -> send/recv -> close。
•	UDP:
服务端:socket -> bind -> recvfrom/sendto -> close。
客户端:socket -> sendto/recvfrom -> close。

9.哈希表的底层实现

“桶”的结构,为在每个元素中维护一个单链表, 然后在单链表上执行元素的插入、搜寻、删除等
操作,每个元素被称为桶。
时间复杂度:理想情况下为O(1)

10.虚函数的三种调用方式

 1: 指针
void test1(myclass *p)
{
    p->go();
}

/2: 引用
void test2(myclass &p)
{
    p.go();
}

3: 对象
void test3(myclass my)
{
    my.go();
}

11.C++11的几个特性

1.初始化列表 Initializer List:所有STL容器都支持初始化列表
2.统一的初始化方法 Uniform Initialization,可以统一使用大括号{}进行初始化。
**3.类型推导 Auto Type
**4.遍历 foreach   (for(auto i:nums))
5.空指针 nullptr,以往我们使用NULL表示空指针。它实际上是个为0的int值。为此C++ 11新增类
型nullptr_t,它只有一个值nullptr。
6.构造函数的相互调用 
7.禁止重写 final
8.显式声明重写 override
9.默认构造函数 default
10.删除构造函数 delete
**11.Lambda函数
这是个非常强大的重量级功能。简单地讲,就是可以用它定义一个临时的函数对象,它像其它对
象一样可以传递和保存。更为强大的是,它甚至可以访问当前函数的上下文。

std::vector<int> v = { 5, 10, 15, 20 };
print(v, [](int i) { return i > 10; });     // 输出 15 20
[]中,可以用=表示按值传递,&表示按引用传递,[a, &b]	a为值传递,b为引用传递

12.智能指针

unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权。无法使两个
unique_ptr指向同一个对象,但是可以进行移动构造和移动赋值操作。
share_ptr资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。调用release()
时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。
weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两
个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加
对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过
调用lock函数来获得shared_ptr。

13.STL中vector的内存分配机制

vector有一个特点就是:内存空间只会增长不会减少。vector有两个函数,一个是capacity(),返
回对象缓冲区(vector维护的内存空间)实际申请的空间大小,另一个size(),返回当前对象缓冲
区存储数据的个数。对于vector来说,capacity是永远大于等于size的,档capacity和size相等时
,vector就会扩容,capacity变大。在调用push_back时,若当前容量已经不能够放入心得元素
(capacity=size),那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当
中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存。
所以说这个过程的效率是极低的,为了避免频繁的分配内存,C++每次申请内存都会额外的增
长。
发布了5 篇原创文章 · 获赞 0 · 访问量 139

猜你喜欢

转载自blog.csdn.net/weixin_42369779/article/details/104564155