题很多,先上题后上答案,便于大家思考。

一.拼多多服务端实习岗位面试

1、 一个C++源文件从文本到可执行文件经历的过程

2、#include 的顺序以及尖叫括号和双引号的区别

3、进程和线程,为什么要有线程

4、C++11有哪些新特性

5、malloc的原理,brk系统调用干什么的,mmap呢

6、C++的内存管理方式,STL的allocator,最新版本默认使用的分配器

7、hash表的实现,包括STL中的哈希桶长度常数。

8、hash表如何rehash,怎么处理其中保存的资源

9、Redis的rehash怎么做的,为什么要渐进rehash,渐进rehash怎么实现的

10、Redis的定时机制怎么实现的,有哪些弊端,你将如何改进这个弊端

11、Redis是单线程的,为什么这么高效

12、Redis的数据类型有哪些,底层怎么实现

13、Redis和memcached的区别

14、TCP的模型,状态转移

15、用过哪些设计模式,单例模式,观察者模式的多线程安全问题

16、用过多线程吗,以前的多线程代码还能怎么优化,线程池的实现

17、epoll怎么实现的,reactor模型组成

18、线程间的同步方式,最好说出具体的系统调用

19、哈希表的桶个数为什么是质数,合数有何不妥?

答案分析:

1、 一个C++源文件从文本到可执行文件经历的过程

对于C/C++编写的程序,从源代码到可执行文件,一般经过下面四个步骤:

1).预处理,产生.ii文件

2).编译,产生汇编文件(.s文件)

3).汇编,产生目标文件(.o或.obj文件)

4).链接,产生可执行文件(.out或.exe文件)

2、#include 的顺序以及尖叫括号和双引号的区别

1. #include的顺序的区别:

头文件的引用顺序对于程序的编译还是有一定影响的。如果要在文件a.h中声明一个在文件b.h中定义的变量,而不引用b.h。那么要在a.c文件中引用b.h文件,并且要先引用b.h,后引用a.h,否则汇报变量类型未声明错误,也就是常见的某行少个“;”符号。

2. #include尖括号和双引号的区别:

1)#include<> ,认为该头文件是标准头文件。编译器将会在预定义的位置集查找该头文件,这些预定义的位置可以通过设置查找路径环境变量或者通过命令行选项来修改。使用的查找方式因编译器的不同而差别迥异。

2)#include"",认为它是非系统头文件,非系统头文件的查找通常开始于源文件所在的路径。查找范围大于<>。

3、进程和线程,为什么要有线程

1、和进程相比,它是一种非常"节俭"的多任务操作方式。在linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。(资源)

2、运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需时间也远远小于进程间切换所需要的时间。据统计,一个进程的开销大约是一个线程开销的30倍左右。(切换效率)

3、线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进城下的线程之间贡献数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。

(通信) 除以上优点外,多线程程序作为一种多任务、并发的工作方式,还有如下优点:

1、使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。(CPU设计保证)

2、改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序才会利于理解和修改。(代码易维护)

4、C++11有哪些新特性

1)关键字及新语法:auto、nullptr、for

2)STL容器:std::array、std::forward_list、std::unordered_map、std::unordered_set

3)多线程:std::thread、std::atomic、std::condition_variable

4)智能指针内存管理:std::shared_ptr、std::weak_ptr

5)其他:std::function、std::bind和lamda表达式

5、malloc的原理,brk系统调用干什么的,mmap呢

malloc的实现方案:

1)malloc函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。

2)调用malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。 然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。

3)调用free函数时,它将用户释放的内存块连接到空闲链表上。

4)到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段, 那么空闲链表上可能没有可以满足用户要求的片段了。于是,malloc()函数请求延时,并开始在空闲链表上检查各内存片段,对它们进行内存整理,将相邻的小空闲块合并成较大的内存块。

brk和mmap:

从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。

1、brk是将数据段(.data)的最高地址指针_edata往高地址推;

2、mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。

这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。

在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。

6、C++的内存管理方式,STL的allocator,最新版本默认使用的分配器

C++的内存管理方式:

在c++中内存主要分为5个存储区:

栈(Stack):局部变量,函数参数等存储在该区,由编译器自动分配和释放.栈属于计算机系统的数据结构,进栈出栈有相应的计算机指令支持,而且分配专门的寄存器存储栈的地址,效率分高,内存空间是连续的,但栈的内存空间有限。

堆(Heap):需要程序员手动分配和释放(new,delete),属于动态分配方式。内存空间几乎没有限制,内存空间不连续,因此会产生内存碎片。操作系统有一个记录空间内存的链表,当收到内存申请时遍历链表,找到第一个空间大于申请空间的堆节点,将该节点分配给程序,并将该节点从链表中删除。一般,系统会在该内存空间的首地址处记录本次分配的内存大小,用于delete释放该内存空间。

全局/静态存储区:全局变量,静态变量分配到该区,到程序结束时自动释放,包括DATA段(全局初始化区)与BSS段(全局未初始化段)。其中,初始化的全局变量和静态变量存放在DATA段,未初始化的全局变量和静态变量存放在BSS段。BSS段特点:在程序执行前BSS段自动清零,所以未初始化的全局变量和静态变量在程序执行前已经成为0.

文字常量区:存放常量,而且不允许修改。程序结束后由系统释放。程序代码区:存放程序的二进制代码

SGI 版本STL的默认配置器std::alloc参见:

《STL源码剖析》

1)考虑到小型区块所可能造成的内存碎片问题,SGI设计了双层配置器。第一级配置器直接使用malloc()和free();第二级则视情况采取不同的策略:当配置区块超过128bytes时,视为“足够大”,便调用第一级配置器;当配置区块小于128bytes时,视之为“过小”,为了降低额外负担,便采用memory pool(内存池)整理方式,而不在求助于第一级配置器。

2)内存池的核心:内存池和16个自由链表(各自管理8,16,...,128bytes的小额区块)。在分配一个小区块时,首先在所属自由链表中寻找,如果找到,直接抽出分配;若所属自由链表为空,则请求内存池为所属自由链表分配空间;默认情况下,为该自由链表分配20个区块,若内存池剩余容量不足,则分配可分配的最大容量;若内存池连一个区块都无法分配,则调用chunk_alloc为内存池分配一大块区块;若内存不足,则尝试调用malloc分配,否则返回bad_alloc异常。

7、hash表的实现,包括STL中的哈希桶长度常数。

hash表的实现主要涉及两个问题:散列函数和碰撞处理。1)hash function (散列函数)。最常见的散列函数:f(x) = x % TableSize .

2)碰撞问题(不同元素的散列值相同)。解决碰撞问题的方法有许多种,包括线性探测、二次探测、开链等做法。SGL版本使用开链法,使用一个链表保持相同散列值的元素。虽然开链法并不要求表格大小必须为质数,但SGI STL仍然以质数来设计表格大小,并且将28个质数(逐渐呈现大约两倍的关系)计算好,以备随时访问,同时提供一个函数,用来查询在这28个质数之中,“最接近某数并大于某数”的质数。

8、hash表如何rehash,怎么处理其中保存的资源

先想想为什么需要rehash:

因为,当loadFactor(负载因子)<=1时,hash表查找的期望复杂度为O(1). 因此,每次往hash表中添加元素时,我们必须保证是在loadFactor <1的情况下,才能够添加。

模仿C++的vector扩容方式,Hash表中每次发现loadFactor==1时,就开辟一个原来桶数组的两倍空间(称为新桶数组),然后把原来的桶数组中元素全部转移过来到新的桶数组中。注意这里转移是需要元素一个个重新哈希到新桶中的。

9、Redis的rehash怎么做的,为什么要渐进rehash,渐进rehash怎么实现的

为了避免rehash对服务器造成影响,服务器不是一次将ht[0]里面的所有键值对全部rehash到ht[1],而是分多次、渐进式地将ht[0]里面的键值对慢慢地rehash到ht[1].

以下是哈希表渐进式rehash的详细步骤:

为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。

在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示rehash工作正式开始。

在rehash进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对rehash到 ht[1] , 当rehash工作完成之后, 程序将 rehashidx 属性的值增一。

随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被rehash至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示rehash操作已完成。

渐进式rehash的好处在于它采取分而治之的方式, 将rehash键值对所需的计算工作均滩到对字典的每个添加、删除、查找和更新操作上, 从而避免了集中式rehash而带来的庞大计算量。

10、Redis的定时机制怎么实现的,有哪些弊端,你将如何改进这个弊端

Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:文件事件(服务器对套接字操作的抽象)和时间事件(服务器对定时操作的抽象)。Redis的定时机制就是借助时间事件实现的。

一个时间事件主要由以下三个属性组成:id:时间事件标识号;when:记录时间事件的到达时间;timeProc:时间事件处理器,当时间事件到达时,服务器就会调用相应的处理器来处理时间。一个时间事件根据时间事件处理器的返回值来判断是定时事件还是周期性事件。

弊端:Redis对时间事件的实际处理时间并不准时,通常会比时间事件设定的到达事件稍晚一些。

改进:多线程?一个处理文件事件,一个处理时间事件? (不确定)。

11、Redis是单线程的,为什么这么高效

虽然Redis文件事件处理器以单线程方式运行,但是通过使用I/O多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与Redis服务器中其他同样以单线程运行的模块进行对接,这保持了Redis内部单线程设计的简单性。

1)字符串:整数值、embstr编码的简单动态字符串、简单动态字符串(SDS)

2)列表:压缩列表、双端链表

3)哈希:压缩列表、字典

4)集合:整数集合、字典

5)有序集合:压缩列表、跳跃表和字典

13、Redis和memcached的区别

Redis和memcached的区别:

1)数据类型 :redis数据类型丰富,支持set liset等类型;memcache支持简单数据类型,需要客户端自己处理复杂对象

2)持久性:redis支持数据落地持久化存储;memcache不支持数据持久存储。

3)分布式存储:redis支持master-slave复制模式;memcache可以使用一致性hash做分布式。

4)value大小不同:memcache是一个内存缓存,key的长度小于250字符,单个item存储要小于1M,不适合虚拟机使用

5)数据一致性不同:redis使用的是单线程模型,保证了数据按顺序提交;memcache需要使用cas保证数据一致性。CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作

6)cpu利用:redis单线程模型只能使用一个cpu,可以开启多个redis进程

14、TCP的模型,状态转移

TCP四层模型:

状态转移:

熟悉三次握手 和 四次释放的TCP状态转移。

设计模式

1)TemplateMethod模式:《effectivec++》 条款35 :借助Non-virtualInterface手法实现TemplateMethod模式

2)Strategy模式:《effectivec++》 条款35:借助FunctionPointers实现Strategy模式、借助std::function完成Strategy模式、古典Strategy模式

16、用过多线程吗,以前的多线程代码还能怎么优化,线程池的实现

线程的创建#include

int pthread_create(pthread_t *restrict thread,

const pthread_attr_t *restrict attr,

void *(*start_routine)(void*),

void *restrict arg);

线程终止:

从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。

一个线程可以调用pthread_cancel终止同一进程中的另一个线程。

线程可以调用pthread_exit终止自己。

线程池的实现:https://pan.baidu.com/s/1qHUhyCLFzHuHaio7-PAYiQ 密码:emmq

17、epoll怎么实现的,reactor模型组成

epoll实现:

第一步:epoll_create()系统调用。此调用返回一个句柄,之后所有的使用都依靠这个句柄(eventpoll的对象)来标识。structeventpoll{

....

/*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/

structrb_rootrbr;

/*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/

structlist_headrdlist;

....

};

第二步:epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。

第三部:epoll_wait()系统调用。通过此调用收集收集在epoll监控中已经发生的事件。

Reactor模型:

1)Handle:即操作系统中的句柄,是对资源在操作系统层面上的一种抽象,它可以是打开的文件、一个连接(Socket)、Timer等。由于Reactor模式一般使用在网络编程中,因而这里一般指Socket Handle,即一个网络连接。

2)Synchronous Event Demultiplexer(同步事件复用器):阻塞等待一系列的Handle中的事件到来,如果阻塞等待返回,即表示在返回的Handle中可以不阻塞的执行返回的事件类型。这个模块一般使用操作系统的select来实现。

3)Initiation Dispatcher:用于管理EventHandler,即EventHandler的容器,用以注册、移除EventHandler等;另外,它还作为Reactor模式的入口调用SynchronousEventDemultiplexer的select方法以阻塞等待事件返回,当阻塞等待返回时,根据事件发生的Handle将其分发给对应的EventHandler处理,即回调EventHandler中的handle_event()方法。

4)EventHandler:定义事件处理方法:handle_event(),以供InitiationDispatcher回调使用。

5)ConcreteEventHandler:事件EventHandler接口,实现特定事件处理逻辑。

18、线程间的同步方式,最好说出具体的系统调用

1)互斥量(mutex)#include

int pthread_mutex_destroy(pthread_mutex_t *mutex);          //销毁

int pthread_mutex_init(pthread_mutex_t *restrict mutex,

const pthread_mutexattr_t *restrict attr);          //初始化

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int pthread_mutex_lock(pthread_mutex_t *mutex);            //上锁

int pthread_mutex_trylock(pthread_mutex_t *mutex);          //尝试上锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);

2)条件变量(Condition Variable)#include

int pthread_cond_destroy(pthread_cond_t *cond);            //销毁

int pthread_cond_init(pthread_cond_t *restrict cond,

const pthread_condattr_t *restrict attr);            //初始化

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_timedwait(pthread_cond_t *restrict cond,

pthread_mutex_t *restrict mutex,

const struct timespec *restrict abstime);

int pthread_cond_wait(pthread_cond_t *restrict cond,

pthread_mutex_t *restrict mutex);

int pthread_cond_broadcast(pthread_cond_t *cond);

int pthread_cond_signal(pthread_cond_t *cond);

3)信号量(Semaphore)#include

int sem_init(sem_t *sem, int pshared, unsigned int value);

int sem_wait(sem_t *sem);

int sem_trywait(sem_t *sem);

int sem_post(sem_t * sem);

int sem_destroy(sem_t * sem);

————————————————

调用sem_wait()可以获得资源,使semaphore的值减1,如果调用sem_wait()时semaphore的值已经是0,则挂起等待。如果不希望挂起等待,可以调用sem_trywait()。调用sem_post()可以释放资源,使semaphore的值加1,同时唤醒挂起等待的线程。

19、哈希表的桶个数为什么是质数,合数有何不妥

质数比合数更容易避免冲撞,也就是说使用质数时,哈希效果更好,原始数据经哈希后分布更均匀。版权声明:本文为CSDN博主「Damage233」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/Damage233/article/details/81116115

还有腾讯,阿里,京东等一线大厂面试题及答案整理,因篇幅有限,需要集锦的朋友可以后台私信我免费获取。

c++软件开发面试旋极面试题_c++开发程序员面试拼多多面试题整理(含答案)相关推荐

  1. python面试技巧和注意事项_Python 程序员面试须知须会的5个问题

    原标题:Python 程序员面试须知须会的5个问题 作为一个程序员,可能或多或少经历过一些技术面试,有些是编程语言本身的问题,有些是跟工程相关的问题.今天我们来总结关于Python程序员面试的时候经常 ...

  2. 面试者面试官,双向角度的程序员面试指南!

    作者 | Noj Vek  译者 | 弯月 出品 | 程序人生(ID:coder _life) 本文作者经历过 100 多场面试,而且也担任过 50 多场面试的面试官,我们一起来看一看他从面试者与面试 ...

  3. Java基础易错面试题,初级程序员面试必看!(会不断更新)

    写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字.我热爱技术.热爱开源.热爱编程.技术是开源的.知识是共享的. 这博客是对自己学习的一点点总结及记录,如果您对 Java.算法 感兴 ...

  4. java get方法报空指针_面试的哪些事儿之JAVA程序员面试笔试题(一)

    前言 在一个技术微信群看一个网友最近在一家公司做笔试的题目,然后我就整理了一下,供大家参考一下,希望能够帮助到大家. 笔试内容 1.假设有一个mysql实例,相关信息如下: schema名为test用 ...

  5. 程序员面试金典适合java么,【程序员面试金典】面试题 01.03. URL化(示例代码)

    题目 URL化.编写一种方法,将字符串中的空格全部替换为%20.假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的"真实"长度.(注:用Java实现的话,请使用字符数组实现 ...

  6. java程序员面试能穿束脚裤吗_程序员面试,应该怎么穿?

    我面试过很多人,我也面试过好几次.对于穿着来讲,我个人觉得干净得体就好,没有什么特别的. 把自己收拾得干净些,不要听那个抖机灵的回答.一个人留给别人的第一映像非常重要,邋遢肯定是扣分项.我说的是自信, ...

  7. java程序猿面试问缺点怎么回答_JAVA程序员面试32问,你能回答多少题

    第一,谈谈final, finally, finalize的区别. 第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements ...

  8. java面试问题答不上来_程序员面试的时候突然遇到答不上的问题怎么办?

    前言 今天给大家讲讲面试过程当中最长遇到的窘境,也是最能体现一个候选人临场应变能力的地方,那就是当我们在面试的过程当中,遇到的问题回答不上来的时候,该怎么办. 误区 在开始讲解之前,先纠正一个误区,那 ...

  9. python程序员面试宝典:12个Python程序员面试必备问题与答案

    @本文来源于公众## 标题号:csdn2299,喜欢可以关注公众号 程序员学府 文章目录 1. 什么是pickling和unpickling? 2. 什么是Python的命名空间? 3. args,k ...

  10. 2020年程序员面试必备书单,这一篇整理齐了

    又到了找工作的季节,大多数程序员却无比纠结,想跳槽却不想面试.毕竟拼实力没啥可怕,怕的是明明有实力,面试时却有口难言. 不少小伙伴在后台询问程序员找工作或者跳槽要做什么准备? 面试就像作战,只要做好充 ...

最新文章

  1. SAP SD基础知识之流程概览
  2. springboot yaml/yml配置文件字符串换行
  3. 30行代码AC——例题6-3 矩阵链乘(Maxtrix Chain Multiplication, UVa 442)——解题报告
  4. 旋转数组中的最小元素 java_程序员算法面试题之旋转数组的最小值
  5. centos安装禅道的步骤
  6. java 工厂模式详解_java 工厂模式的实例详解
  7. 你的第一个 iOS 应用 – 2.开始上手
  8. qbytearray初始化全0_【小白学PyTorch】4.构建模型三要素与权重初始化
  9. OpenCV3学习(4.2)——图像常用滤波方法(方框、均值、高斯、中值、双边)
  10. 计算直方图中面积最大的矩形
  11. MVC过滤器详解 面向切面编程(AOP)
  12. dede WAP 版 限制标题title的字数的方法
  13. python画图代码乔治-2020阅读书单
  14. 微信小程序-image(图片)
  15. [随笔] flex 布局使用 space-between 尾行排版效果优化
  16. 计算机网上培训6,wordexcel计算机基础培训6.pptx
  17. [高通SDM450][Android9.0]CTA认证--去除某些应用开机使用定位权限
  18. H265编码视频流媒体播放器EasyPlayer.js支持9宫格视频同屏播放的写法
  19. echarts 柱状图数值为0时 显示柱体
  20. 原生图片预览实现及由此引出的图片自适应宽高问题探索

热门文章

  1. CAD转换器,转换JPG图片
  2. Openstack容器项目之Magnum
  3. 【高并发】高并发分布式锁架构解密,不是所有的锁都是分布式锁(升级版)!!
  4. SolidWorks Composer居然可以让医疗设备的开发时间缩短60%?!
  5. 运维部知识库管理办法V1版
  6. 冰点还原精灵可以支持1T大硬盘
  7. 历史著作《万历十五年》的优秀读后感范文3200字
  8. SAP 公司间关联交易 外向交货单自动生成内向交货单报错:处理的单位XXXXXXX已经入库.无法进行分配
  9. VeryCD下载服务关闭 CEO感叹7年心血说停就停
  10. 【设计】】MOS管衬底电位接法|PMOS、NMOS衬底连接-KIA MOS管