1.
1.1 你理解的编程规范?
- 命名: 变量的定义不可以随便定义,变量的命名要通过它本身的作用来进行一个定义,方便理解。
- 注释: 注释的内容主要包含:做什么,怎么做,怎么用等等,对边界的条件特殊的情况进行说明。
- 类以及函数的规模:类和函数最好不要面向过程编程,功能功能尽量分离。
- 缩进 类成员和函数之间,用空行分隔开。
1.2 操作系统的进程之间的通信
- 管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有沁园关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
- 有名管道: 有名管道也会半双工的通信方式,但是它允许无亲缘关系进程间的通信。
- 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 消息队列: 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
- 共享内存: 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存
由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对进程间通信方式运行效率低而设计的,往往与其他通信机制,如信号量等使用。 - 套接字: 套接字是一种进程间通信机制,与其他通信机制不同的是,它可用于不用及其间的进程通信。
2.
2.1 操作系统虚拟内存
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存,而实际上,它通常是被分隔为多个物理内存碎片,还有部分暂时存储在外部磁盘储存器上,在需要的时候进行数据交换。
为什么使用虚拟内存?
- 安全:如何用用户程序可用直接访问物理内存,会造成安全问题。虚拟内存技术使得同时驻留在内存的多个用户进程相互之间不会发送干扰,也不会访问操作系统所占有的空间。
- 扩大程序的地址空间:利用虚拟存储技术,从逻辑上对内存空间进行扩充,从而可以使得用户在较小的内存里运行较大的程序。好像每个程序都拥有足够大的私有的物理内存。
- 为用户提供方便:逻辑地址和物理地址分开,用户只在格子的逻辑地址空间编写程序,不必关心物理地址的细节,地址的转换由底层硬件和操作系统自动完成。
3.
3.1 进程线程区别
- 调度:线程是系统调度的基本单位,程序是资源分配的基本单位。
- 拥有资源:进程是拥有资源的基本单位,隶属于进程之间可以并发执行,而且多个线程之间也可以并发执行从而使操作系统具有更好的并发性,提高系统的吞吐量。
- 并发性:在引入线程的操作系统中,不仅进程之间可以并发执行,而且多个线程之间也可以并发执行,从而使操作系统具有更好的并发性,提高系统的吞吐量。
- 系统开销:线程切换时只需要保存和设置少量寄存器内容,开销很小。此外,由于同一进程内的多个线程共享进程的地址空间,因此这些线程之间的同步与通信非常容易实现,甚至无需操作系统的干预。
- 地址空间和其他资源。进程的地址空间之间互相独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其他进程不可见。
- 通信方面:进程间通信(IPC)需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以直接读/写进程数据来通信。
- 进程间不会相互影响,但是一个进程内的线程如果挂掉了,则其他线程全部挂掉。
3.2 如何实现多线程
4.
4.1 引用和指针的区别
- 初始化要求不同。引用在创建的时候同时必须初始化,即引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值。
- 可修改性不同。引用一旦别初始化为指向一个对象,它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是改变它和原始对象的绑定关系。
- 不存在NULL引用,引用不能使用指向空值的引用,它必须总是指向某个对象;而指针则可以是NULL,不需要总是指向某些对象,可以把指针指向任意的对象,所以指针更加灵活,也容易出错。
- 测试需要的区别。由于引用不会指向空值,这意味着使用引用之前不需要测试它的合法性;而指针则需要精彩测试。因此使用引用的代码效率比使用指针的要高。
- 应用的区别。如果是指一旦指向一个对象后就不会改变指向,那么应该使用引用。如果有存在指向NULL或在不同的时刻指向不同的对象这些可能性,应该使用指针。
4.2 字节序的概念
4.3 枚举类型的大小
int 大小
4.4 enum和struct的区别
struct里面可以自定义类型,而且类型可以不同,但是enum里面只能是同一种类型,而且值的顺序是默认递增的。
4.5 结构体的对齐方式?判断一个结构体的大小?如何强制不对齐?
用#pragma pack (1)将STRUCT_T定义为1字节对齐方式。
4.6 堆内存与栈内存
根据《C++ 内存管理技术内幕》一书,在C++中,内存分成5个区,他们分别是堆,栈,自由存续区,全局/静态存续区,常量存续区。
-
栈:内存由编译器在需要时自动分配和释放。通常用来存储局部变量和函数参数。(为运行函数而分配的局部变量、函数参数、返回地址等存放在栈区)。栈运算分配内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
-
堆:内存使用new进行分配,使用delete或delete[]释放。如果未能对内存进行正确的释放,会造成内存泄漏。但在程序结束时,会由操作系统自动回收。
-
自由存储区:使用malloc进行分配,使用free进行回收。和堆类似。
-
全局/静态存储区:全局变量和静态变量被分配到同一块内存中,C语言中区分初始化和未初始化的,C++中不再区分了。(全局变量、静态数据、常量存放在全局数据区)
-
常量存储区:存储常量,不允许被修改。
这里,在一些资料中是这样定义C++内存分配的,可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。
-
静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
-
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
-
堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或 delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。
4.7 内存泄漏
5.
5.1 深拷贝与浅拷贝
如果拷贝的对象中引用了某个外部的内容(例如分配在堆上的数据),那么在拷贝主峰对象的时候,让新旧两个对象指向同一个外部的内容,就是浅拷贝。如果在拷贝的这个对象的时候为新对象制造了外部对象的独立拷贝,那么就是深拷贝。
5.2 类模板优缺点
比较通用
5.3 递归会有什么影响
一、效率
递归中有可能很多计算都是重复的,从而对性能带来很大的影响。递归的本质是把一个问题分解成多个小问题。如果多个小问题存在相互重叠的部分,那么就存在重复的计算。比如“斐波那契数列”。
二、空间
除了效率之外,递归还有可能引起更严重的问题:调用栈溢出。每个进程的栈的容量是有限的,当递归调用的层级太多时,就会超出栈的容量,从而导致栈举出。
5.4 DHCP
5.5 ping
6.
6.1 const static的作用,堆栈区
const用来声明变量以及函数指针等,static声明静态变量,变量保存在静态存储区,如果是函数的话,是在类中实现的,而且静态成员函数只能访问静态变量,因为它没有this指针。
堆栈区,堆区是需要程序员动态维护的,使用new和delete/malloc和free,栈区是编译器维护的,存放函数内定义的一些变量。
6.2 指针占几个字节,int占几个字节。
32 : int 4个字节 指针 4个字节
64 : int 4个字节 指针 8个字节
6.3 了解多态吗?
多态性的定义:统一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
- 编译时的多态性。编译时的多态性是指通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
- 运行时的多态性。运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C++中,运行时的多态性通过虚成员实现。
6.4 常函数是干嘛的?
常函数用来维护函数体里面的变量,使得它们不会被修改,只能读不能写。
评论区