操作系统
用户态和内核态
用户态和内核态是CPU两种状态代表两种权限。 当CPU出于安全考虑,在用户状态下无权执行特权指令。
程序与过程的区别
程序是静态的,过程是动态的,程序是存储在某种介质上的二进制代码,对应于程序执行过程
进程和线程
多过程与多线程的区别
对比维度 | 多进程 | 多线程 | 总结 |
---|---|---|---|
数据共享,同步 | 复杂的数据共享需要使用IPC;数据是分开的,同步简单 | 由于共享过程数据,数据共享很简单,但同步也很复杂 | 各有优势 |
内存、CPU | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 线程占优 |
创建销毁和切换 | 创造复杂的销毁和切换速度 | 创建销毁,切换简单,速度快 | 线程占优 |
编程、调试 | 编程简单,调试简单 | 编程复杂,调试复杂 | 进程占优 |
可靠性 | 过程不会相互影响 | 挂断一个线程会导致整个过程挂断 | 进程占优 |
分布式 | 适用于多核多机分布式;如果一台机器不够,扩展到多台机器相对简单 | 适用于多核分布式 | 进程占优 |
有没有阻塞和唤醒线程?
有,得不到cpu它会被阻塞,无法获得系统资源将导致过程堵塞
为什么线程切换成本小
切换过程时需要切割页面表,通常伴随着页面调度 在统一的线程共享过程中,线程只需保存线程的上下文(相关寄存器状态和堆栈信息)
内存模型的过程
线程共享什么内存空间?
堆叠、动态库、全局变量、打开文件
线程同步的方法有哪些?
- 相互排斥:采用相互排斥对象机制,只有相互排斥对象的线程才有权访问资源。由于只有一个相互排斥的对象,因此可以确保公共资源不会同时问
- 信号量:信号量允许多个线程同时访问同一资源,但应控制最大线程量
- 事件:通过通知操作保持多线程同步,可以轻松实现多线程优先级比较
谈谈各种锁
每次拿数据都会上锁(实现系统互斥)
- 重量级锁:无锁,立即进入堵塞状态(场景:实际竞争,锁竞争时间长)
- 自旋锁:无法获得锁、循环等固定时间,然后进入堵塞状态
- 自适应自旋锁: 等待时间根据线程最近的锁状态进行调整
不需要加锁,如果发生冲突,想办法解决
- 轻量级锁:使用前版本号设置标记,退出后重置标记(无实际竞争,多线交替使用锁;允许短锁竞争)
- 偏向锁:使用的线程将在第一次进入时记录ID,退出不变。 (偏向锁适用于一直只执行一个线程的情况。
乐观地解决冲突:版本号控制。当数据被修改时,版本号将被修改 1.提交更新时,如果您读取的版本号与数据库不同,则需要重新提交更新。
堆栈的区别
- 栈是自动分配的,速度快,堆需要手动回收,速度慢。
- 栈的最大容量是固定的,空间小,堆的大小受系统中有效虚拟内存的限制,空间大
- 栈从高地址扩展到低地址,堆从低地址扩展到高地址
- 栈是连续空间,堆是不连续空间
- 栈是线程私有的,堆是线程公有的
编程在多线程环境下需要注意哪些情况?
避免死锁
避免死锁的方法有哪些?
剥夺死锁的四个必要条件:互斥条件、不剥夺条件、请求和维护条件、循环等待条件 银行家算法 检测和解除
静态库和动态库的区别?
从源代码到可执行文件的程序一般可分为四个步骤:
- 预处理(Prepressing):预处理过程主要从源代码#开始处理预编译指令
- 编译(Compilation):在编译过程中,对预处理的文件进行词法、语法和语义分析,并生成相应的汇编代码文件
- 汇编(Assembly):汇编过程将汇编代码文件翻译成机器可执行的目标文件
- 链接(Linking):将汇编生成的目标文件集合连接到链接过程中,生成最终的可执行文件。
库是可执行代码的二进制形式,可由操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。
- 在编译过程中,静态库将与目标文件打包生成可执行文件。而动态库在运行过程中链接载入。
- 静态库移植性好,不依赖外部。
- 静态库浪费空间,多个程序调用同一个库,则只需要保留一份
- 静态库不方便更新
虚拟内存,为什么要有虚拟内存,虚拟内存是如何映射到物理内存的
当每个过程创建和加载时,将分配一个连续的虚拟地址空间。在过程眼中,这个空间是真实和有效的,但它实际使用的内存空间往往小于虚拟内存,而且是不连续的暂时不使用的数据将被放入磁盘中。
优点:提高内存利用率
虚拟内存通过页面映射到物理内存,页面是记录虚拟内存与物理内存映射关系的数据结构。
虚拟内存页面中有什么?
内存块号:一个页号对应的内存块号 状态位:标记页面是否在内存中 访问字段:记录最近几次访问,为页面置换算法提供参考 修改位:标记页面是否被修改过,如果被修改过则再换出的时候需要更新外存 外存地址:外存中页面的地址
如果访问内存中的页表不命中,需要做什么操作?
缺页中断将由操作系统从外存转移到内存。如果内存不足,则通过页面置换算法选择最近不使用的页面来转移内存
页面置换算法是什么?
从产生到运行的整个过程
从源代码到可执行文件的程序一般可分为四个步骤:
- 预处理(Prepressing):预处理过程主要从源代码#开始处理预编译指令
- 编译(Compilation):在编译过程中,对预处理的文件进行词法、语法和语义分析,并生成相应的汇编代码文件
- 汇编(Assembly):汇编过程将汇编代码文件翻译成机器可执行的目标文件
- 链接(Linking):将汇编生成的目标文件集合连接到链接过程中,生成最终的可执行文件。
计算机网络
怎么理解TCP/IP协议
应用层 传输层 网络层 数据链路层
TCP三次握手的过程,原因
A–>B同步包(SYN=1,seq=x) A<–B确认 同步包(SYN=1,ACK=1,seq=y,ack=x 1) A–>B确认包(ACK=1,seq=x 1,ack=y 1)
第三次握手是为了防止无效的连接请求到达服务器,让服务器错误地打开连接。
如果客户端发送的连接请求留在网络中,服务器端发回的连接确认将需要很长时间。客户端等待超时重传时间后,会要求重新连接。但是,滞留的连接请求最终会到达服务器。如果不握手三次,服务器将打开两个连接。如果有第三次握手,客户端将忽略服务器后发送的连接确认,而不是第三次握手,因此不会再次打开连接。
TCP四次挥手,为什么要有TIME_WAIT状态?为什么要等待2MLS?
A–>B终止(FIN)包 A<–B确认(ACK)包(此时A–>B的通道就释放了) A<–B终止(FIN)包 A–>B确认(ACK)包(此时A<–B的通道就释放了)
- 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文
TCP和UDP有什么区别
UDP (1)UDP不需要建立连接。 (2)UDP不保证可靠交付,也不使用拥塞控制。 (3)UDP是面向报文的,适合多媒体通信的要求。 (4)UDP支持一对一,一对多,多对一,多对多交互通信。 (5)UDP首部开销小,只有8个字节。
TCP (1)TCP需要建立连接。(三次握手) (2)TCP提供可靠交付,使用拥塞控制 (3)TCP面向字节流:把应用程序交付下来的数据看成一连串无结构的字节流。 (4)TCP只支持只一对一。 (5)TCP提供全双工通信。
输入网址进入网页按回车刷新网页都发生了什么
- 【用户】输入 URL
- 【浏览器】从 URL 中解析出 主机名
- 【浏览器】将 主机名 转换成 服务器ip地址(先查找本地DNS缓存列表,没有的话再向默认的DNS服务器发送查询请求并缓存)
- 【浏览器】从 URL 中解析出 端口号
- 【浏览器】与 目标服务器 建立 TCP连接(三次握手)
- 【浏览器】向 服务器 发送一条 HTTP请求报文
- 【服务器】向 浏览器 返回一条 HTTP响应报文
- 【浏览器】关闭连接(四次挥手)
- 【浏览器】解析文档,渲染成页面
渲染页面
- 解析html生成DOM树
- 解析css生成css树
- 将两个树合成,生成渲染树(遍历每个可见节点,让后对每个可见节点找到适配的CSS样式规则并应用)
- 渲染树布局(遍历渲染树,确认每个元素在页面上的大小和位置)
- 渲染树绘制 (遍历渲染树,调用渲染器的paint()方法)
HTTP无状态如何记录我们的登录状态
基于Session实现的会话保持 在会话开始时(客户端第一次像服务器发送http请求),服务器将会话状态保存起来(本机内存或数据库中),然后分配一个会话标识(SessionId)给客户端,这个会话标识一般保存在客户端Cookie中,以后每次浏览器发送http请求都会带上Cookie中的SessionId到服务器,服务器拿到会话标识就可以把之前存储在服务器端的状态信息与会话联系起来,实现会话保持(如果遇到浏览器禁用Cookie的情况,则可以通过url重写的方式将会话标识放在url的参数里,也可实现会话保持)
基于Cookie实现的会话保持 基于Cookie实现会话保持与上述基于Session实现会话保持的最主要区别是前者完全将会话状态信息存储在浏览器Cookie中,这样一来每次浏览器发送HTTP请求的时候都会带上状态信息,因此也就可以实现状态保持。
建立一个http连接之后如何让网络变得更快
讲一下http和https的区别
http传输的是明文,https传输密文 http端口号80,https端口号443 https协议需要到CA证书 https = http + SSL
讲一下https连接建立过程
- 首先客户端发起请求到服务端,服务端处理后发送一个公钥给客户端
- 客户端进行验证公钥,看公钥是否有效和是否过期
- 客户端验证通过会产生随机值key,然后用公钥进行加密回传给服务端
- 服务端用私钥解密后获得客户端的随机值key
- 利用随机值key加密数据后传输给客户端
- 客户端利用key值进行解密数据
- 客户端获取真正的数据
HTTPS抓包原理
- 客户端向服务器发起HTTPS请求,被中间人截获
- 中间人伪装成客户端向服务器发起请求
- 服务器将证书发给中间人
- 中间人获得证书,生成假证书替换掉真正书发给客户端
- 客户端生成随机对称密钥,用假证书中的公钥加密后发给服务器,被中间人截获
- 中间人用假证书的私钥解密获得对称密钥,用真正公钥加密发给服务器
- 服务器用私钥解密获得对称密钥,链接建立,之后发送的数据都用对称密钥加密解密。
http状态码
200 - 请求成功 301 - 资源(网页等)被永久转移到其它URL 302 - 临时重定向 404 - 请求的资源(网页等)不存在 500 - 内部服务器错误
分类 | 分类描述 |
---|---|
1** | 信息,服务器收到请求 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
http 1.1和2.0的区别
- 1.1基于文本,2.0基于二进制数据帧
- 2.0使用了首部压缩,节省了带宽
- 2.0多路复用的,只需一个连接即可实现并行
- 2.0有服务端推送,客户端请求资源时,服务器会把相关的资源一起发送过去
一个TCP支持多少个HTTP?了解HTTP复用吗?
TCP支持任意数量http http1.1之前,每次请求都需要建立连接 http1.1之后,在发送http的请求头中设置Connection: keep-alive,连接会长时间保持。 但是在同一个tcp连接中,新的请求需要等上次请求收到响应后,才能发送。
http和tcp的关系
http建立在tcp的基础上 当你打电话时,TCP协议是电话线的电信号传输协议,而HTTP协议是普通话,如果TCP连接不通,意味着你电话没打通,如果HTTP协议不遵守,就是你打通了不说话,或者说方言。
get与post请求的区别,post的安全性体现在那里,是否可以发现他的请求内容
- GET把参数包含在URL中,POST通过request body传递参数
- GET请求在URL中传送的参数是有长度限制的,而POST 么有。
- GET请求只能进行url编码,而POST支持多种编码方式
- 对参数的数据类型, GET只接受部分ASCII字符,而 POST没有限制。
- GET请求会被 浏览器主动缓存,而POST需要手动设置。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET比POST更不安全,因为参数 直接暴露在URL上,所以不能用来传递敏感信息。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被做成书签,而POST不可以。
- GET产生一个TCP数据包;POST可能会产生两个TCP数据包。这个是由客户端决定的, 如果POST内容过多,会先发送头部,再发送参数
介绍一下DNS协议
DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转换的服务。 域名具有层次结构,从上到下依次为:根域名、顶级域名、二级域名。
- 根域名服务器: 知道所有的顶级域名服务器的域名和IP地址。
- 顶级域名服务器: 负责管理自己下面注册的所有二级域名服务器
- 权限域名服务器: 负责一个区的域名服务器
- 本地域名服务器: 当一个主机发出DNS请求时,这个查询请求报文就是发送给了本地域名服务器
DNS解析流程
- 主机先向本地域名服务器进行递归查询
- 本地域名服务器采用迭代查询,向一个根域名服务器进行查询
- 根域名服务器告诉本地域名服务器,下一次应该查询的顶级域名服务器的IP地址
- 本地域名服务器向顶级域名服务器进行查询
- 顶级域名服务器告诉本地域名服务器,下一步查询权限服务器的IP地址
- 本地域名服务器向权限服务器进行查询
- 权限服务器告诉本地域名服务器所查询的主机的IP地址
- 本地域名服务器最后把查询结果告诉主机
DNS劫持
解析域名的时候,DNS服务器返回了一个错误的地址
- DDOS攻击:在知道攻击目标的IP地址后,攻击者以这个地址为源地址去向DNS服务器发送请求,然后攻击目标就会收到很多DNS返回的请求
- 缓存污染:如果将数据放入有漏洞的服务器缓存中,当进行DNS请求的时候,就会将缓存信息返回给用户
- 中间人攻击:通过截获主机与DNS服务器之间的通信,伪装成DNS服务器向主机返回错误的ip
TCP如何保证可靠传输
TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。 ARQ协议:每发完一个分组就停止发送,等待对方确认。超过一段时间仍然没有收到确认就重传。信道利用率低 连续ARQ协议:发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。不能向发送方反映出接收方已经正确收到的所有分组的信息
流量控制(滑动窗口)
TCP 连接的每一方都有固定大小的缓冲空间,发送方和接收方各有一个窗口,窗口的大小限制了数据的传输速率。接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小,从而达到流量控制的目的。
如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离。接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。接收窗口只会对窗口内最后一个按序到达的字节进行确认
TCP协议的流量控制机制,滑窗为0时,怎么办
发送方停止发送数据
滑动窗口与拥塞窗口的区别
滑动窗口是接收方建议的窗口大小,只考虑了接受方的承载力 拥塞窗口是根据网络状况自己调整的窗口大小,考虑的是网络的承载力
拥塞控制
发送方会维护一个拥塞窗口,发生拥塞就变小,否则变大 TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。 传输开始的时候,拥塞窗口会被设为1,并且会设置一个慢开始门限 每次收到确认以后,拥塞窗口就会翻倍 当拥塞窗口大于等于慢开始门限的时候,每次确认只会加1 如果出现超时的情况,慢开始门限设为拥塞窗口的一半,拥塞窗口变为1 在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。 在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。 在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,慢开始门限设为拥塞窗口的一半,拥塞窗口减半
TCP协议切片
https://www.cyc2018.xyz/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%20-%20%E4%BC%A0%E8%BE%93%E5%B1%82.html#tcp-%E9%A6%96%E9%83%A8%E6%A0%BC%E5%BC%8F
如何实现断点续传?
http中Header 里添加两个参数来实现的。这两个参数分别是客户端请求时发送的 Range 和服务器返回信息时返回的 Content-Range
从原理层面解释下为什么我们用不了咕鸽
在咱们国家到国外的防火墙上,设置一个类似白名单的东西,不在白名单的IP地址一律不可以把包发送到国外
C/S模型,socket的建立过程(bind/listen那一套,顺便说了accept和connect是在tcp握手的什么时间返回)
电脑接入局域网,如何分配ip
- 主机生成 DHCP 请求报以(0.0.0.0)为源地址进行广播
- DHCP服务器收到广播后,根据MAC地址返回IP 地址、DNS 服务器的 IP 地址、默认网关路由器的 IP 地址和子网掩码
数据结构与算法
快排如何优化
采用三数取中法选择基准 取收尾中间元素,取中值作为基准,避免选到最大值最小值。 序列长度小于一定值后用插入排序,如长度=10 在一次分割结束后,把与基准值相等的元素聚到一起,不参与下次分割。
哈希冲突如何解决
- 开放定址法
- 链地址法
- 再哈希法
红黑树基本概念
- 每个节点或是黑色或是红色
- 根节点是黑色
- 每个叶节点是黑色(叶节点为空节点)
- 如果一个节点是红色,则它的子节点必须是黑色
- 每个节点到该节点的所有叶节点的路径包含相同数目的黑色节点
编译原理
函数调用流程
https://zhuanlan.zhihu.com/p/25149493
每一个在对应一个结构(call stack) 程序中每一个对应一个(stack frame),栈帧中保存函数、传递给被调函数的等信息 栈底对应高地址,栈顶对应低地址,栈由内存高地址向低地址生长
然后cpu中有一些一些特殊的寄存器
- ax(accumulator): 可用于存放
- bp(base pointer): 用于存放执行中的函数对应的栈帧的
- sp(stack pointer): 用于存放执行中的函数对应的栈帧的
- ip(instruction pointer): 指向当前执行指令的
在调用一个函数时
- 传递被调用函数的参数:x86架构的cpu会把参数压入调用栈中,而x86_64架构的cpu会把参数存到通用寄存器中。
- 当前函数的下一条指令,即的值入栈,这个是被调函数返回后的地址
- 修改的值为的执行位置
- 会首先把当前函数栈帧栈底地址,也就是bp存放的值压入调用栈
- 然后建立新的栈帧,将被调用的函数栈帧栈底地址存到bp中,正式进入被调用函数
- 将传入的参数存为函数内局部变量
- 函数执行完之后最后结果保存在ax寄存器中
- 销毁当前栈帧,sp栈顶指针回退回bp栈底,将栈顶元素出栈赋值给bp,退回到原函数的栈帧内。
- 将栈顶元素出栈赋值给ip寄存器,指向原函数栈帧中将要执行的下一条指令地址
IDE如何判断代码哪一行报错
面向对象
面向对象三大特征
把客观的事物封装成抽象的类。类可以设置自身属性和方法的可见性,对外隐藏细节 可以在现有类的基础上扩展它的功能 允许将子类类型的指针赋值给父类类型的指针。
继承多态如何实现
https://blog.csdn.net/djl806943371/article/details/88677634
继承和多态的区别是什么
继承是静态绑定,多态是动态绑定。
设计模式
懒汉式
volatile的作用
- 使变量内存可见,就是说当一个共享变量在一个线程中被修改,其他线程能够立即得到变量的最新值。为什么说不加volatile线程就得不到最新值了呢,因为java的内存模型中,线程有自己的工作内存,与主内存隔离,共享变量存在主内存中,线程使用的仅仅是共享变量的一个副本,所以说会出现更新不及时的情况。
- 另外一个作用是防止指令重排序。为了提高性能,编译器和处理器会在不影响单线程结果的情况下对指令做重排序,但是这样会在多线程下引发一些安全问题。 synchronized的作用是防止多个线程同一时间调用此代码块或者方法.
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){
};
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){
};
public static Singleton getInstance() {
return instance;
}
}
将对象的创建逻辑封装起来,由一个工厂对象代替创建。
public interface Shape {
void draw();
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square");
}
}
public class ShapeFactory {
public shape getShape(String shapeName) {
if (shapeName.equalsIgnoreCase("Rectangle")) {
return new Rectangle();
}
else if (shapeName.equalsIgnoreCase("Square")) {
return new Square();
}
else {
return null;
}
}
}
设计原则
- 开闭原则。一个软件实体,应该对外开放扩展,对内修改关闭。开闭原则的优点在于可以在不改动原有代码的前提下给程序扩展功能。增加了程序的可扩展性,同时也降低了程序的维护成本
- 里氏替换原则。在一个系统中,用子类对象替换其父类对象,系统的执行效果应该不变。子类可以扩展父类的功能,但不能改变父类原有的功能。是实现开闭原则的重要方式之一
- 合成复用原则。在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。维持了类的封装性,降低了类之间的耦合度,是实现开闭原则的重要方式之一
- 单一职责原则。一个类或者一个函数只允许有一个职责,即只有一个导致该类变更的原因。如果类与方法的职责划分的很清晰,不但可以提高代码的可读性,更实际性地更降低了程序出错的风险,因为清晰的代码会让bug无处藏身,也有利于bug的追踪,也就是降低了程序的维护成本。
- 接口分离原则。多个特定的客户端接口要好于一个通用性的总接口。客户端不应该依赖它不需要实现的接口。这样可以使接口责任划分更加明确,实现高内聚低耦合
- 依赖倒置原则。细节应该依赖抽象。高层模块不能依赖低层模块,二者都应该依赖抽象。尽量不要从实体类中继承,这样可以降低类之间的耦合度,提高系统的可扩展性以及可维护性
- 迪米特法则。一个对象应该对尽可能少的对象有接触,也就是只接触那些真正需要接触的对象。降低类与类之间的耦合
C++
指针和引用的区别
- 指针是一个存储地址实体,而引用仅是个别名
- 引用初始化后不能被改变,指针可以改变所指的对象
- 引用不能为空,指针可以为空。
const
-
const修饰变量,使变量的值不可变,变量必须初始化
-
const修饰指针,左定值,右定向
int a = 8; const int * const p = &a;
-
const修饰参数,既可使指针不篡改,也可const &不调用复制构造
-
const修饰返回值,不能被赋值和修改
-
const修饰类成员函数,防止成员函数修改被调用对象的值
C++继承和多态是如何实现的
通过访问限定符:public,protected,private来实现 通过虚函数的重写以及父类的指针和引用指向子类的对象
C++如何判断机器是64还是32
32位指针占4字节,64位指针占8字节 sizeof(int *)
或者
int main(void)
{
void *a, *b;
cout << (char *)(&a) - (char *)(&b) << endl;
return 0;
}
C++对象的内存分布是怎样的
- 非静态成员变量放在对象体内
- 非静态成员函数放在程序的静态数据区内
- 静态成员放在程序的静态数据区内
new一个对象都发生了什么?
- 分配内存空间
- 初始化成员变量
- 调用构造方法
C++的构造函数、析构函数、复制构造函数、符号重载
https://blog.csdn.net/weixin_50168448/article/details/113613371
string类赋值运算符是深拷贝还是浅拷贝
深拷贝
C++纯虚函数
基类中不能实现,相当于接口。
虚函数、虚表、虚指针
虚函数主要是用来实现多态的。子类重写了父类的虚函数,用父类指针接受子类对象,调用该函数,用的是子类的函数。 当一个类有虚函数时,成员中就会有一个虚指针,虚指针指向虚表,虚表中保存着虚函数的地址。继承多个类会有多个虚指针,也会有多个虚表。当子类重写父类虚函数时,重写函数的地址会覆盖虚表中原来父类虚函数的地址。 当调用对象的虚函数时,会通过查表来运行。
虚函数能不能inline
不能,虚函数是运行时才能确定调用哪个,而inline是在编译期对函数进行展开
右值引用是什么,移动构造函数有什么好处
C++thread里面的锁,条件变量,讲一下怎么用他们实现生产者消费者模型
static关键字
- 函数内static局部变量:变量在程序初始化时被分配,直到程序退出前才被释放
怎么判断大小端;
怎么在main函数之前和之后执行代码
main之前的工作
- 配置堆栈
- 初始化静态和全局变量
- 为未初始化部分的全局变量赋值
- 运行全局构造器 所以,可以在全局变量的构造器内执行代码 之后用atexit(func)
#define与inline的区别
#define 只进行简单的字符替换,无类型检测 typedef:定义类型别名 用于处理复杂类型 inline: 内联函数对编译器提出建议,是否进行宏替换,编译器有权拒绝
字节对齐
许多计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(通常是2,4或8)的倍数。这种对齐限制简化了形成处理器和存储器系统之间的接口的硬件设计
智能指针
智能指针是由类来实现的,当超出了类的实例对象的作用域时,对象的析构函数会自动调用。通过类的析构函数来自动销毁指针管理的内存。 c++11 的智能指针包括unique_ptr,shared_ptr, weak_ptr, 这三种,其中auto_ptr 已被遗弃。 unique_ptr保证同一时间内只有一个智能指针可以指向该对象 shared_ptr使用引用计数的智能指针。引用计数的智能指针可以跟踪引用同一个真实指针对象的智能指针实例的数目。这意味着,可以有多个std::shared_ptr实例可以指向同一块动态分配的内存,当最后一个引用对象离开其作用域时,才会释放这块内存。 weak_ptr在指向一个对象的时候不会增加其引用计数
shared_ptr循环引用问题
class Person {
public:
Person(const string& name): m_name{
name} {
cout << m_name << " created" << endl;
}
virtual ~Person(){
cout << m_name << " destoryed" << endl;
}
friend bool partnerUp(std::shared_ptr<Person>& p1, std::shared_ptr<Person>& p2){
if (!p1 || !p2){
return false;
}
p1->m_partner = p2;
p2->m_partner = p1;
cout << p1->m_name << " is now partenered with " << p2->m_name << endl;
return true;
}
private:
string m_name;
std::shared_ptr<Person> m_partner;
};
int main() {
auto p1 = std::make_shared<Person>("Lucy");
auto p2 = std::make_shared<Person>("Ricky");
partnerUp(p1, p2); // 互相设为伙伴
return 0;
}
以上的程序输出为:
Lucy created
Ricky created
Lucy is now partnered with Ricky
p1和p2都没有释放,发生了内存泄漏。 解决方案:将类内指针shared_ptr换为weak_ptr,程序输出将是
Lucy created
Ricky created
Lucy is now partnered with Ricky
Ricky destroyed
Lucy destroyed
其他
git版本控制的原理
工作区、暂存区、库
git为什么要有暂存区
- 修改进入暂存区就进入git管理范围,修改就不会丢失了,而且方便回退
- 保持日志的干净,暂存区可以用来保存一些还没有完成的任务的修改,这些修改如果马上进入仓库的话会导致一个任务有多条commit记录。
JS 和 Swift 的区别
- Swift 为 强类型、静态类型;JavaScript 为 弱类型、动态类型
mvc,mvp,mvvm的区别
Model: 用于封装数据以及对数据的处理方法 View: 渲染页面 Controller: 连接M和V,用于控制应用程序的流程,及页面的业务逻辑
- View 传送指令到 Controller ;
- Controller 完成业务逻辑后,要求 Model 改变状态 ;
- Model 将新的数据发送到 View,用户得到反馈。
MVP(Model-View-Presenter)是MVC的改良模式
- M、V、P之间双向通信。
- View 与 Model 不通信,都通过 Presenter 传递。 安卓用的就是MVP 与MVP不同的是,V和VM是双向绑定的。
心理测试
自我评价
人生理想
职业规划
平时怎么学习
缺点优点
智力题
4位数乘以4后会得到它的反转,这个数是啥
设四位数ABCD. ABCD × 4 = DCBA 显然,由积的个位看出,A是偶数,至少为2,又由积的千位看出,D≤9,推得A = 2 研究乘数 与 乘积的个位 D × 4 = …A = …2 推得D = 8
2BC8 × 4 = 8CB2的性质 ,列方程得: (2008 + 100B + 10C)×4 = 8002 + 100C + 10B 化简整理得: 1+13B = 2C 结合B、C的范围和奇偶性可知,B 必 = 1,C = 7 综上解得ABCD = 2178
5位数21978 6位数219978 7位数2199978
甲乙轮流抛硬币,正面胜,先抛的人优势多大?
设甲先抛。设甲胜率为x。当且仅当甲第一次抛出反面时乙才有获胜的机会,而此时乙又变成先抛,所以乙的胜率应该是0.5x,因x + 0.5x = 1, x = 2 3 x = {2\over3} x=32
六十四匹马,八个跑道,找出最快的四匹马
详解
有 n 个灯泡,编号1…n,初始全灭,然后1的倍数的灯泡切换一次状态(亮 / 暗),2的倍数的灯泡切换一次状态,…n的倍数的灯泡切换一次状态。问最后有多少个灯泡亮着?
(1)依题意,灯泡按过的次数等于其编号的所有因数的个数; (2)开始状态是熄的,后来是亮的,说明按过的次数是奇数; (3)所有因数的个数为奇数的自然数只有完全平方数。 综上,编号是完全平方数的灯泡最后是亮的。
前端
css画三角形
div {
height: 0px;
width: 0px;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 50px solid blue;
background-color: white;
}
css垂直居中
https://www.jianshu.com/p/7bbc4860a45c
css position属性值有哪些
- static:默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
- absolute:以最近的已定位父元素为参考系,脱离文档流
- fixed:相对于浏览器窗口进行定位,脱离文档流
- relative:存在于文档流,占用空间不变,相对于其正常位置进行定位
- sticky:在文档流中占据位置,但是当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置
以下代码输出
问题
var func1 = x => x var func2 = x => { x } var func3 = x => ({ x }) console.log(func1(1)) console 标签:
bp93420ie压力变送器