腾讯 C 笔试/面试题及答案
扫描二维码
随时随地手机看文章
题很多,先上题后上答案,便于大家思考
问题点:
1、C和C 的特点与区别?
2、C 的多态
3、虚函数实现
4、C和C 内存分配问题
5、协程
6、CGI的了解
7、进程间通信方式和线程间通信方式
8、TCP握手与释放
9、http和https的区别?
10、虚拟内存的概念与介绍
11、单链表的反转算法
12、红黑树以及其查找复杂度
13、KPM字符串匹配
14、TCP超时等待、重传以及流量控制
15、数据库引擎
16、数据库索引
1、C和C 的特点与区别?
答:(1)C语言特点:1.作为一种面向过程的结构化语言,易于调试和维护;2.表现能力和处理能力极强,可以直接访问内存的物理地址;3.C语言实现了对硬件的编程操作,也适合于应用软件的开发;4.C语言还具有效率高,可移植性强等特点。(2)C 语言特点:1.在C语言的基础上进行扩充和完善,使C 兼容了C语言的面向过程特点,又成为了一种面向对象的程序设计语言;2.可以使用抽象数据类型进行基于对象的编程;3.可以使用多继承、多态进行面向对象的编程;4.可以担负起以模版为特征的泛型化编程。C 与C语言的本质差别:在于C 是面向对象的,而C语言是面向过程的。或者说C 是在C语言的基础上增加了面向对象程序设计的新内容,是对C语言的一次更重要的改革,使得C 成为软件开发的重要工具。2、C 的多态
答:C 的多态性用一句话概括:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。1):用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数;2):存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的;3):多态性是一个接口多种实现,是面向对象的核心,分为类的多态性和函数的多态性。;4):多态用虚函数来实现,结合动态绑定.;5):纯虚函数是虚函数再加上 = 0;6):抽象类是指包括至少一个纯虚函数的类;纯虚函数:virtual void fun()=0;即抽象类,必须在子类实现这个函数,即先有名称,没有内容,在派生类实现内容。3、虚函数实现
答:简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例:4、C和C 内存分配问题
答:(1)C语言编程中的内存基本构成C的内存基本上分为4部分:静态存储区、堆区、栈区以及常量区。他们的功能不同,对他们使用方式也就不同。1.栈 ——由编译器自动分配释放;2.堆 ——一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收;3.全局区(静态区)——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(C 中已经不再这样划分),程序结束释放;4.另外还有一个专门放常量的地方,程序结束释放;(a)函数体中定义的变量通常是在栈上;(b)用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上;(c)在所有函数体外定义的是全局量;(d)加了static修饰符后不管在哪里都存放在全局区(静态区);(e)在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用;(f)在函数体内定义的static表示只在该函数体内有效;(g)另外,函数中的"adgfdf"这样的字符串存放在常量区。(2)C 编程中的内存基本构造在C 中内存分成5个区,分别是堆、栈、全局/静态存储区、常量存储区和代码区;1、栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区,里面的变量通常是局部变量、函数参数等。2、堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。3、全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C 里面没有这个区分了,他们共同占用同一块内存区。4、常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。5、代码区 (.text段),存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。内存模型组成部分:自由存储区,动态区、静态区;根据c/c 对象生命周期不同,c/c 的内存模型有三种不同的内存区域,即:自由存储区,动态区、静态区。自由存储区:局部非静态变量的存储区域,即平常所说的栈;动态区:用new ,malloc分配的内存,即平常所说的堆;静态区:全局变量,静态变量,字符串常量存在的位置;注:代码虽然占内存,但不属于c/c 内存模型的一部分;一个正在运行着的C编译程序占用的内存分为5个部分:代码区、初始化数据区、未初始化数据区、堆区 和栈区;(1)代码区(text segment):代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),如果反复,则需要使用跳转指令,如果进行递归,则需要借助栈来实现。注意:代码区的指令中包括操作码和要操作的对象(或对象地址引用)。如果是立即数(即具体的数值,如5),将直接包含在代码中;(2)全局初始化数据区/静态数据区(Data Segment):只初始化一次。(3)未初始化数据区(BSS):在运行时改变其值。(4)栈区(stack):由编译器自动分配释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。(5)堆区(heap):用于动态内存分配。为什么分成这么多个区域?主要基于以下考虑:#代码是根据流程依次执行的,一般只需要访问一次,而数据一般都需要访问多次,因此单独开辟空间以方便访问和节约空间。#未初始化数据区在运行时放入栈区中,生命周期短。#全局数据和静态数据有可能在整个程序执行过程中都需要访问,因此单独存储管理。#堆区由用户自由分配,以便管理。还有腾讯,阿里,京东等一线大厂面试题及答案整理,因篇幅有限,需要集锦的朋友可以 qun720209036免费获取。
5、协程
答:定义:协程是一种用户态的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置;线程是抢占式,而协程是协作式;协程的优点:跨平台跨体系架构无需线程上下文切换的开销无需原子操作锁定及同步的开销方便切换控制流,简化编程模型高并发 高扩展性 低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。协程的缺点:无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU;进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序:这一点和事件驱动一样,可以使用异步IO操作来解决。6、CGI的了解
答:CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。CGI通信系统的组成是两部分:一部分是html页面,就是在用户端浏览器上显示的页面。另一部分则是运行在服务器上的Cgi程序。7、进程间通信方式和线程间通信方式
答:(1)进程间通信方式:# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。# 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。# 消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。# 套接字( socket ) :套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。(2)线程间通信方式:#全局变量;#Messages消息机制;#CEvent对象(MFC中的一种线程通信对象,通过其触发状态的改变实现同步与通信)。8、TCP握手与释放
答:(1)握手#第一次握手:主机A发送握手信号syn=1和seq=x(随机产生的序列号)的数据包到服务器,主机B由SYN=1知道,A要求建立联机;#第二次握手:主机B收到请求后要确认联机信息,向A发送syn=1,ack=x(x是主机A的Seq) 1,以及随机产生的确认端序列号seq=y的包;#第三次握手:主机A收到后检查ack是否正确(ack=x 1),即第一次发送的seq 1,若正确,主机A会再发送ack=y 1,以及随机序列号seq=z,主机B收到后确认ack值则连接建立成功;#完成三次握手,主机A与主机B开始传送数据。注:上述步骤中,第二和第三次确认包中都还包含一个标志位未予以说明,该标志位为1表示正常应答;具体可见图片:9、http和https的区别?
答:HTTPS协议是由SSL HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议,与http主要区别在于:#http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议;#http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443;下面具体介绍一下HTTP和HTTPS协议:首先说明一下:HTTP和HTTPS协议是应用层协议;HTTPS协议、SSL、和数字证书的关系介绍:概述:对于HTTPS协议,所有的消息都是经过SSL协议方式加密,而支持加密的文件正是数字证书;(1)SSLSSL常用的加密算法:对称密码算法、非对称密码算法、散列算法;SSL的加密过程:需要注意的是非对称加解密算法的效率要比对称加解密要低的多。所以SSL在握手过程中使用非对称密码算法来协商密钥,实际使用对称加解密的方法对http内容加密传输;(2)数字证书数字证书是用于在INTERNET上标识个人或者机构身份的一种技术手段,它通过由一些公认的权威机构所认证,从而可以保证其安全地被应用在各种场合。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
10、虚拟内存的概念与介绍
答:虚拟内存中,允许将一个作业分多次调入内存,需要时就调入,不需要的就先放在外存。因此,虚拟内存的实需要建立在离散分配的内存管理方式的基础上。虚拟内存的实现有以下三种方式:#请求分页存储管理#请求分段存储管理#请求段页式存储管理虚拟内存的意义:一,虚拟内存可以使得物理内存更加高效。虚拟内存使用置换方式,需要的页就置换进来,不需要的置换出去,使得内存中只保存了需要的页,提高了利用率,也避免了不必要的写入与擦除;二,使用虚拟地址可以使内存的管理更加便捷。在程序编译的时候就会生成虚拟地址,该虚拟地址并不是对应一个物理地址,使得也就极大地减少了地址被占用的冲突,减少管理难度;三,为了安全性的考虑。在使用虚拟地址的时候,暴露给程序员永远都是虚拟地址,而具体的物理地址在哪里,这个只有系统才了解。这样就提高了系统的封装性。11、单链表的反转算法
答:思想:创建3个指针,分别指向上一个节点、当前节点、下一个节点,遍历整个链表的同时,将正在访问的节点指向上一个节点,当遍历结束后,就同时完成了链表的反转。实现代码:ListNode* ReverseList(ListNode* pHead) {
ListNode *p,*q,*r;
if(pHead==NULL || pHead->next==NULL){
return pHead;
}else{
p=pHead;
q=p->next;
pHead->next=NULL;
while(q!=NULL){
r=q->next;
q->next=p;
p=q;
q=r;
}
return p;
}
}
12、红黑树以及其查找复杂度
答:(1)红黑树来源于二叉搜索树,其在关联容器如map中应用广泛,主要优势在于其查找、删除、插入时间复杂度小,但其也有缺点,就是容易偏向一边而变成一个链表。红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。也就是说,红黑树是在二叉查找树基础上进一步实现的;红黑树的五个性质:性质1. 节点是红色或黑色;性质2. 根节点是黑色;性质3 每个叶节点(指树的末端的NIL指针节点或者空节点)是黑色的;性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点);性质5. 从任一节点到其每个尾端NIL节点或者NULL节点的所有路径都包含相同数目的黑色节点。(注:上述第3、5点性质中所说的NIL或者NULL结点,并不包含数据,只充当树的路径结束的标志,即此叶结点非常见的叶子结点)。因为一棵由n个结点随机构造的二叉查找树的高度为lgn,所以顺理成章,二叉查找树的一般操作的执行时间为O(lgn)。但二叉查找树若退化成了一棵具有n个结点的线性链后,则这些操作最坏情况运行时间为O(n);红黑树虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加以上五个性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。(2)左旋右旋红黑树插入或删除后,一般就会改变红黑树的特性,要恢复红黑树上述5个性质,一般都要那就要做2方面的工作:1、部分结点颜色,重新着色2、调整部分指针的指向,即左旋、右旋。左选右旋如图所示:
左旋,如图所示(左->右),以x->y之间的链为“支轴”进行,使y成为该新子树的根,x成为y的左孩子,而y的左孩子则成为x的右孩子。算法很简单,旋转后各个结点从左往右,仍然都是从小到大。左旋代码实现,分三步:(1) 开始变化,y的左孩子成为x的右孩子;(2) y成为x的父结点;(3) x成为y的左孩子;右旋类似,不再累述;
13、KMP字符串匹配
(1)KMP匹配算法代码实现:int KmpSearch(char* s, char* p)
{
int i = 0;
int j = 0;
int sLen = strlen(s);
int pLen = strlen(p);
while (i < sLen