CrackingtheCodeInterview之C与C++

NO.1 用C++写个方法,打印输入文件的最后K行。

解法:第一种方法,读取文件获取文件总行数,再次读取文件从N-K+1行开始读取直到结束。

第二种方法,使用循环式数组,将读取的每一行放入字符串数组中,当i大于k时,令i mod K作为字符串数组的序号,覆盖原字符串。

NO.2 比较并对比散列表和STL map。散列表是如何实现的?如果输入的数据量不大,可以选用哪些数据结构替代散列表?

解法:散列表就是链表数组,所有插入的数据通过哈希函数找到在数组中的位置,对于冲突的采用拉链法插入到链表的尾部即可,较好的哈希函数会使冲突的数量降到最低,插入时间复杂度为O(N),适用于大批量数据的存储。map是采用平衡二叉查找树实现的,插入时间复杂度为O(logN),当数据量较小时,采用map可替代哈希表。

NO.3 C++虚函数的工作原理是什么?

解答:虚函数的实现需要虚函数表。当类中函数声明为虚的时,就会生成一个vtable,存放这个类的虚函数地址。此外,编译器还会在类里加入隐藏的vptr变量。若子类没有覆写虚函数,该子类的vtable存放父类的虚函数地址,调用这个虚函数时,就会通过vtable解析函数的地址。当子类对象赋值给基类指针时,vptr指向基类虚函数地址,在调用时访问子类的函数,实现类的多态。

NO.4 深拷贝和浅拷贝之间有何区别?请说明两者的用法。

解答:浅拷贝是指只复制对象的成员变量,而深拷贝还会赋值对象的所有指针对象。对于指针的拷贝,浅拷贝只是创建了一个指针,和原来的指针指向同一位置,而深拷贝部件创建了一个新的指针,而且将原指针所指的内存复制到一块新的区域。一般情况下都采用深拷贝,较安全,有些避免大量数据拷贝的时候考虑采用浅拷贝。

NO.5 C语言的关键字“volatile”有何作用?

解答:volatile翻译为易变的,放在变量声明或者定义之前,可以在变量类型之前也可以在之后,同时也可以修饰指针变量,避免编译器优化,每次都会从内存读取来获取新数据,这点对于多线程编程中的全局变量的使用尤为常见,多个线程都有可能改变全局变量的值,所以每次读取使,从内存读取。

NO.6 基类的析构函数为何要声明为virtual?

解答:举例Student是Person的子类,Person* ptr=new Student;,在程序结束时,ptr指针调用基类的析构函数,子类的对象必须得到释放才能避免内存泄露的情况。

NO.7  编写方法,传入参数为指向Node结构的指针,返回传入数据结构的完整拷贝。其中,Node数据结构含有两个指向其他Node的指针。

解法:类似于拷贝一棵树,对于新节点需要动态开辟内存,对于已有节点直接将其位置赋给父节点的next指针即可,为了判断是否已经创建,采用map的数据结构来实现。

NO.8  编写一个只能智能指针类。智能指针是一种数据类型,一般采用模板实现,模拟指针行为的同时还提供自动垃圾回收机制。它会自动记录SmartPointer对象的引用计数,一旦T类型对象的引用计数为0,就会释放该对象。

解法:类的成员变量一个是指针,另一个是引用计数,在创建一个智能指针对象时,需要动态创建一个引用计数,并初始化为1,每次拷贝时,引用计数+1,析构时引用变量-1,当引用计数等于0时,就将智能指针赋值为空,并释放该内存,彻底析构。

NO.9 编写支持对齐分配的malloc和free函数,分配内存时,malloc函数返回的地址必须能被2的n次方整除。

解法:举例,若开辟100字节的内存块,要求起始地址能被16整除,那我们需要额外分配15个字节的内存用于找到被16整除的起始地址,因此malloc多分配15个字节的地址,在初始位置的基础上往下寻找能够被16整除的首地址,并返回该首地址,析构时采用需要析构所有的内存,这是一个问题。我们将首地址的前一个位置赋值为实际的首地址位置,析构的时候直接释放即可。

NO.10  用C编写一个my2DAlloc函数,可分配二维数组。将malloc函数的调用次数降到最少,并确保可通过arr【i】【j】方位该内存。

解法:动态分配指针的指针,然后每个双重指针再动态分配指针,从而实现二维数组,析构是也是先释放指针再释放指针的指针。

你可能感兴趣的:(Interview)