C++面试题目汇总三

it2026-03-07  4

1.main()之前执行的代码

GCC gcc中可以使用attribute关键字,声明constructor和destructor函数。 vc vc中不支持attribute,可插入函数进入初始化函数列表__xi_a,__xi_z和__xc_a,__xc_z由初始化CRTInit()调用。 C++ 全局变量的构造函数在main之前; int g_iValue=func;写在func里面然后去初始化全局变量。

2.缓冲区溢出

  缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢的数据覆盖在合法数据上。   危害:在当前网络与分布式系统安全中,被广泛利用的 50%以上都是缓冲区溢出,其中最著名的例子是 1988 年利用 fingerd 漏洞的蠕虫。 而缓冲区溢出中, 最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在函数返回时改变返回程序的地址,让其跳转到任意地址,带来的危害一种是程序崩溃导致拒绝服务, 另外一种就是跳转并且执行一段恶意代码, 比如得到 shell,然后为所欲为。通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其它指令,以达到攻击的目的。   造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数 。 解决方法 1.在程序的自由存储区中创建并使用动态分配的数组,在C语言中使用malloc(C++中为new)操作符实现,在自由存储空间中创建的动态数组对象是没有名字的,程序员只能通过其地址间接访问堆中的对象。如果程序员能够准备计算出运行时需要的数组长度,就不必再担心因数组变量具有固定的长度而造成的溢出问题。 2. 在C++程序中,采用vector类型和迭代器取代一般的数组和指针访问。利用end操作可以返回迭代器指向vector“末端元素的下一个”,从而充当一个“哨兵”的作用,防止越界调用。

3.Unicode,UTF-8和UTF-16的区别

UTF-16比较好理解,就是任何字符对应的数字都用两个字节来保存。 UTF-8表示一个字符是可变的,有可能是用一个字节表示一个字符,也可能是两个、三个…反正是根据字符对应的数字大小来确定。

4.构造函数中为什么不能调用虚函数

  构造函数中调用一个虚函数的情况,被调用的只是这个函数的本地版本。也就是说,虚机制在构造函数中不工作。   在构造函数中,虚拟机制不会发生作用,因为基类的构造函数在派生类构造函数之前执行,当基类构造函数运行时,派生类数据成员还没有被初始化。如果基类构造期间调用的虚函数向下匹配到派生类,派生类的函数理所当然会涉及本地数据成员,但是那些数据成员没有被初始化,而调用涉及一个对象还没有被初始化的部分自然是很危险的,所以C++会提示此路不通。因此,虚函数不会向下匹配到派生类,而是直接执行基类的函数。

5.程序崩溃的原因

1.读取未赋值的变量 一个变量未初化、未赋值,就读取它的值。( 这属于逻辑问题,往往是粗心大意的导致的 ) 2.函数栈溢出 (1)定义了一个体积太大的局部变量,当变量体积太大时,应该用malloc或new来动态分配内存; (2)函数嵌套调用,层次过深(如无穷递归) 3.数组越界访问 访问数组元素时,下标越界 4.指针的目标对象不可用 (1)空指针 (2)野指针:指针未赋值;free/delete释放了的对象;不恰当的指针强制转换。

6.进程间通讯的四种方式

1.管道(pipe)   管道是一种具有两个端点的通信通道,一个管道实际上就是只存在在内存中的文件,对这个文件操作需要两个已经打开文件进行,他们代表管道的两端,也叫两个句槟,管道是一种特殊的文件,不属于一种文件系统,而是一种独立的文件系统,有自己的数据结构,根据管道的使用范围划分为无名管道和命名管道。 无名管道用于父进程和子进程之间,通常父进程创建管道,然后由通信的子进程继承父进程的读端点句柄和写端点句柄,或者父进程有读写句柄的子进程,这些子进程可以使用管道直接通信,不需要通过父进程。 命名管道,命名管道是为了解决无名管道只能在父子进程间通信而设计的,命名管道是建立在实际的磁盘介质或文件系统(而不是只存在内存中),任何进程可以通过文件名或路径建立与该文件的联系,命名换到需要一种FIFO文件(有先进先出的原则),虽然FIFO文件的inode节点在磁盘上,但仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。 2.信号   信号,用于接受某种事件发生,除了用于进程间通信之外,进程还可以发送信号给进程本身。除了系统内核和root之外,只有具备相同id的进程才可以信号进行通信。 3.消息队列   消息队列是消息的链表,包括Posix消息队列和system v消息队列(Posix常用于线程,system常用于进程),有权限的进程可以向消息队列中添加消息,有读权限的进程可以读走消息队列的消息。 消息队列克服了信号承载信息量少,管道只能承载无格式字节流及缓冲区大小受限等缺陷。 4.共享内存   共享内存使多个进程可以访问同一块内存空间,是最快的IPC形式,是针对其他通信方式运行效率低而设计的,往往与其他进程结合使用,如与信号量结合,来达到进程间的同步与互斥。传递文件最好用共享内存的方式。

7.内联函数失效,使用内联函数的一些限制

类的构造函数不能是虚函数; 类的静态成员函数不能是虚函数; 类的虚函数不能是内联函数; 内联函数不可以做为虚函数(内联函数,构造函数,静态函数时都不能为虚函数的) 内联函数的特点:

一、关键字inline必须与函数定义体放在一起才能使函数成为内联,仅将inline放在函数声明前面不起任何作用。

二、定义在类声明之中的成员函数将自动地成为内联函数。

内联函数的作用:

替代宏,增加代码可读性。

提高代码执行效率。这点和宏的作用相同。原因在于,省略了函数参数压栈出栈和跳转指令了。

使用于部分特殊场合。例如,软件注册码检测。这时候,必须多次检测,而又不能使用一个非内联的检测函数,因为那样一来,破解一处,就等于把软件彻底破解了,所以,使用内联检测,增加破解难度。

内联函数的缺点:增加了编译后的二进制文件的大小。

使用内联函数的一些限制: 1、内联函数中不可含有循环; 2、内联函数中不可含有switch语句; 3、内联函数中不可能含有静态变量; 4、内联函数不可为递归函数; 5、内联函数中不可含有错误处理; 6、如果内联函数调用了其他函数也不会被内联。 7、虚拟函数一般不会内联,但是如果编译器能在编译时确定具体的调用函数,那么仍然会就地展开该函数; 8、如果通过函数指针调用内联函数,那么该函数将不会内联而是通过call进行调用。

使用内联函数的一些注意事项: 1、只在Release版本生效; 2、是基于实现,不是基于声明。

8.什么函数不能是虚函数

类的构造函数不能是虚函数; 类的静态成员函数不能是虚函数; 类的虚函数不能是内联函数; 内联函数不可以做为虚函数(内联函数,构造函数,静态函数时都不能为虚函数的)

9.迭代器失效的情况

10.指针和引用的区别

1、指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元,即指针是一个实体;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已; 2、可以有const指针,但是没有const引用; 3、指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的); 4、指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化; 5、”sizeof引用”得到的是所指向的变量(对象)的大小,而”sizeof指针”得到的是指针本身的大小;

总的来说,在以下情况下你应该使用指针: 1、是你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空); 2、是你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向)。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么你应该使用引用。 3、还有一种情况,就是当你重载某个操作符时,你应该使用引用。

最新回复(0)