最近离职了准备找工作,在网上找了一下C/C++的面试题,看完之后贴在这里整理记录一下
- 【Cisco】那么为什么Delete P[]不需要知道大小?你有什么好的编程实践能让我们有效的进行内存管理。
- 就释放内存来说,编译器是根据指针地址知道某块内存大小的,因为在申请的时候,内存管理器记录了这个地址开始的申请内存的大小
- delete和delete[]的差别只有在数组元素是一个个的对象时,才可以体现出来。因为delete[]可以调用数组中所有对象的析构函数
- 【Cisco】提到内存的分配,简要说一下C++的几个存储区概念以及string、值、引用的内存分配方法
- 一般来讲C++的存储区分为三大块
- 静态存储区(static storage duration):静态变量被分配在此区段,全局变量隐含的是静态的。变量的分配是编译和链接时完成的,但是初始化直到程序中的定义语句处才进行,如果定义时没有提供初始化表达式,则使用默认值初始化。直到程序结束之前,变量不会被销毁。
- 自动存储空间(automatic storage duration):非静态局部变量分配在程序的栈(stack)中,他们程序执行到作用域(scope)的开始处分配空间并且初始化(如果有的话),在离开作用域之前被销毁。因此,变量的创建和销毁是自动完成的,又叫做自动(automatic)变量,你可以在自动变量前使用auto关键字,但是不会产生额外的效果。
- 自由存储区(dynamic storage duration):使用new创建的变量分配在自由存储区(free store),变量的创建和销毁由程序完全的控制,一般使用运行环境(操作系统)提供的功能调用接口完成。
- 一般来讲C++的存储区分为三大块
- 【Cisco】在.NET平台或者J2EE下,有自动内存管理,那么就一定不会造成内存泄露吗?如果有,请你给出你的见解,并阐述在哪几种情况下仍然会有内存泄露。你是否对垃圾回收机制有所了解,它的工作原理是如何,两个平台下的有什么区别。
- 不一定,即使在有垃圾回收机制的平台下,内存泄漏仍然是有可能发生的
- 垃圾回收器是一个级别很低的线程,它通过不定时监测程序使用的内存中被占用的动态分配的内存内的对象是否还存在它的引用来判断是否该回收那个内存单元,如果不存在则回收,否则相反。并不是只要监测到就会回收的,因为垃圾回收器线程的低级别,所以当另一个级别比它高的线程跟他同时竞争运行时间时,前者优先运行,我们通过Thread或者继承Runnable的线程都级别都比它高,所以你无法知道垃圾回收器何时回收
- System.gc()只是建议垃圾回收器进行回收处理,调用它并不能保证它回立即回收。所以即使在存在垃圾回收器的高级语言中,内存泄漏也还是可能存在的,因为垃圾回收器是根据内存中的对象是否还存在它的引用来判断是否该回收这个内存单元。而只要这个对象的引用还存在,就不会释放这块内存。?????这段话的理解还是有疑问的。例如:static Vector pane = new Vector(); pane = null;如果没有其它引用的话,原来pane指向的对象实例就会被回收。
- 简要说一下你知道的避免内存泄漏和排查内存泄漏的方法?
- IBM Rational Purify、BoundsChecker、Valgrind、Insure++及memwatch都是为C/C++程式设计亦较受欢迎的内存除错工具。飞鸽传书垃圾回收则可以应用到任何编程语言,而C/C++也有此类函数库。
- 简单说一下malloc,calloc,realloc,new这几个内存分配函数的区别
- Malloc:void *malloc(unsigned size);分配完内存后,不会对内存进行初始化
- Calloc:void *calloc(size_t nelem, size_t elsize);分配完内存后,会将内存初始化为0.
- Realloc:void *realloc(void *ptr, unsigned newsize);
- 【腾讯】tcp三次握手的过程,accept发生在三次握手哪个阶段?
- accept发生在三次握手之后
- 第一次握手:客户端发送syn包(syn=j)到服务器。
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k)。
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)。
- 三次握手完成后,客户端和服务器就建立了tcp连接。这时可以调用accept函数获得此连接。
- 【腾讯】用UDP协议通讯时怎样得知目标机是否获得了数据包
可以通过如下步骤实现此功能:- 在每个数据包中插入一个唯一的ID,比如timestamp或者递增的int。
- 发送方在发送数据时将此ID和发送时间记录在本地。
- 接收方在收到数据后将ID再发给发送方作为回应。
- 发送方如果收到回应,则知道接收方已经收到相应的数据包;如果在指定时间内没有收到回应,则数据包可能丢失,需要重复上面的过程重新发送一次,直到确定对方收到。
- UDP本身不提供超时重传机制,要实现该功能需要在应用层做些手脚
- 【腾讯】求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。(网友给出的答案,待完善)
- 思路:
- 一天总共有 3600*24 = 86400秒。
- 定义一个长度为86400的整数数组int delta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。
- 然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。这样处理一遍后数组中存储了每秒中的人数变化情况。
- 定义另外一个长度为86400的整数数组int online_num[86400],每个整数对应这一秒的论坛在线人数。
- 假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0] = delta[0]。第n+1秒的人数online_num[n] = online_num[n-1] + delta[n]。
-
这样我们就获得了一天中任意时间的在线人数。
-
- 思路:
-
【腾讯】在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。(网友给出的答案,待完善)
- 不妨假设10G个整数是64bit的。
- 2G内存可以存放256M个64bit整数。
- 我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。
- 如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。
- 首先明明是256M个,2G byte / 8byte = 256M
- 其次,这是笔试题,考的是思路,2G内存是完全可用的,不包括操作系统占用的部分
- 第三,硬件厂商对内存是1024进制的,不是1000进制的。只有硬盘和网络设备才是1000进制的
- 【腾讯】两个整数集合A和B,求其交集。
- 利用map来解决。
- 读取整数集合A中的整数,并将读到的整数插入到map中。
- 读取整数集合B中的整数,如果该整数在map中,则将此数加入到交集当中。
- 考虑到重复的话,可以将步骤稍微改进一下:
- 读取整数集合A中的整数,将读到的整数插入到map中,并将对应的值设为1。
- 读取整数集合B中的整数,如果该整数在map中并且值为1,则将此数加入到交集当中,并将在map中的对应值改为2。
- 通过更改map中的值,避免了将同样的值输出两次。
- 利用map来解决。