差不多得了
ssss
ssss
C++指针和内存泄漏的问题
指针是C++中用于存储内存地址的变量,不当使用指针可能导致内存泄漏,如动态分配内存后未释放。解决方法是使用智能指针或确保手动释放内存。
你觉得智能指针最好的思想在哪?你实现过智能指针吗?shared_ptr,包括循环引用,多线程情形下的问题
智能指针的核心思想是自动管理内存,避免手动管理带来的内存泄漏问题。shared_ptr通过引用计数实现内存共享,但可能存在循环引用导致内存泄漏,可使用weak_ptr解决。多线程环境下需要考虑线程安全问题,可使用互斥锁保护引用计数。
多线程,那你谈一下你的理解吧?
多线程是指在一个程序中同时运行多个线程,每个线程执行不同的任务。多线程可以提高程序的并发性能,但也带来了线程安全、同步等问题。
TCP/IP你说一下吧?HTTP这样的典型的request和response的方式更符合人的习惯,那为什么还需要TCP这样的连接呢?你觉得现在让你来设计一下TCP这个协议,你觉得不足在哪里,你会怎样做呢
TCP/IP是一组协议,TCP提供可靠的、面向连接的传输服务。HTTP基于TCP,TCP的连接特性保证了数据传输的可靠性。TCP的不足包括建立连接开销大、传输效率相对较低等,可考虑优化连接建立过程、提高传输效率等。
HTTP,服务端是不知道何时发送完毕的,那么怎么判断接收已经完成了呢?
可以通过Content-Length字段指定消息体长度,或使用分块传输编码(Chunked Transfer Encoding),服务端以特定格式发送数据块,客户端根据结束标记判断接收完成。
同步和异步IO的区别。
同步IO中,应用程序发起IO操作后会阻塞,直到操作完成;异步IO中,应用程序发起IO操作后继续执行其他任务,IO完成后通过回调或通知机制告知应用程序。
epoll怎么判断数据读取完毕?
epoll可以通过返回的事件判断是否有可读数据,当读取到的数据长度小于请求读取的长度,或者接收到EOF(文件结束符)时,可认为数据读取完毕。
new 和 malloc的区别?有malloc了为什么还要设置new,new还有哪些用法?
new是C++的运算符,用于对象的动态分配,会调用构造函数;malloc是C语言的函数,仅分配内存。new还可以进行定位new操作,在指定内存位置构造对象。
为什么要设置虚析构函数?虚析构函数的作用。
当通过基类指针删除派生类对象时,如果基类析构函数不是虚函数,只会调用基类析构函数,可能导致派生类资源未释放。虚析构函数可以确保正确调用派生类析构函数,释放资源。
TCP 和 UDP的区别? 面向连接的连接的含义?
TCP是面向连接的、可靠的、基于字节流的传输协议;UDP是无连接的、不可靠的、基于数据报的传输协议。面向连接意味着在传输数据前需要建立连接,传输完成后断开连接,保证数据的可靠传输。
private 有多态吗? 引用有多态吗?
private成员函数不能实现多态,因为多态通过虚函数实现,而private成员函数不能被外部访问。引用可以实现多态,通过基类引用指向派生类对象,调用虚函数时会根据实际对象类型调用相应的函数。
web 服务器的作用?服务器的处理流程?
Web服务器的作用是接收客户端的HTTP请求,处理请求并返回响应。处理流程一般包括接收请求、解析请求、处理请求(如查询数据库、调用业务逻辑)、生成响应、发送响应。
日志系统的实现,为什么采用两块缓冲区,而不是把缓冲区的大小扩大。好处是什么。
采用两块缓冲区可以实现异步日志写入。一块缓冲区用于前端记录日志,另一块缓冲区用于后端写入磁盘。当一块缓冲区写满后,交换两块缓冲区,避免了前端记录日志时的阻塞,提高了性能。
日志来不及写,怎么处理。
可以采用丢弃部分日志、增大缓冲区、异步写入、使用消息队列等方法处理日志来不及写的情况。
线程池的处理逻辑,怎么判断一个线程挂掉,怎么实现负载均衡。
线程池的处理逻辑包括创建一定数量的线程、将任务放入任务队列、线程从队列中取出任务执行。判断线程挂掉可以通过异常捕获、返回值检查等方式。实现负载均衡可以采用任务分配算法,如轮询、根据线程负载分配等。
对智能指针的理解。
智能指针是一种类模板,用于管理动态分配的内存,自动释放不再使用的内存,避免内存泄漏。常见的智能指针有unique_ptr、shared_ptr、weak_ptr。
怎么处理失效和过期的请求。
可以为请求设置过期时间,定期检查请求队列,删除过期请求;也可以在处理请求时判断请求是否过期,若过期则返回错误信息。
如果没有空闲的工作线程,新到的请求怎么办?
可以将新请求放入任务队列等待,或者根据策略拒绝请求,如返回错误信息或采用过载保护机制。
怎么处理下载请求。下载的数据大小都不一致。怎么支持浏览器。
可以采用分块传输,根据浏览器的请求范围返回相应的数据块;支持断点续传,记录已下载的位置,方便用户继续下载。
介绍一下对深度学习的理解。
深度学习是机器学习的一个分支,通过构建多层神经网络模型,自动从大量数据中学习特征和模式,用于图像识别、语音识别、自然语言处理等领域。
网络的时延和抖动。
网络时延是指数据从发送端到接收端所需的时间,包括传播时延、处理时延、排队时延等。抖动是指数据包延迟的变化,可能导致音视频卡顿等问题。
怎么快速计算网络的带宽,上行速度。
可以通过发送一定大小的数据包,记录发送和接收时间,根据数据包大小和时间差计算带宽。上行速度可以通过上传文件等方式进行测试。
什么是线程安全,怎么实现线程安全,有哪些方式。
线程安全是指多个线程访问共享资源时,不会出现数据不一致或其他错误。实现线程安全的方式包括使用互斥锁、信号量、原子操作等。
线程中有哪些锁。
常见的线程锁有互斥锁(mutex)、读写锁(read-write lock)、自旋锁(spin lock)、递归锁(recursive mutex)等。
虚析构函数的作用。
确保通过基类指针删除派生类对象时,能正确调用派生类的析构函数,释放派生类资源。
stl里面有哪些迭代器。
STL中有输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。
智能指针。
用于自动管理动态内存,防止内存泄漏,常见的有unique_ptr、shared_ptr、weak_ptr。
time_wait有什么作用。
TIME_WAIT状态确保最后一个ACK包能被对方收到,防止数据包丢失导致对方重传;也能让旧的数据包在网络中自然消失,避免影响新的连接。
TCP粘包怎么处理。
可以在消息头中指定消息长度、使用分隔符、采用固定长度消息等方法处理TCP粘包问题。
用过哪些进程通信方式。
常见的进程通信方式有管道(pipe)、命名管道(named pipe)、消息队列(message queue)、共享内存(shared memory)、信号量(semaphore)等。
socket中怎么使用相同的端口号。
可以设置SO_REUSEADDR选项,允许在同一端口上绑定多个套接字;也可以使用不同的IP地址或协议来区分不同的连接。
树有哪些遍历方法,平衡二叉树的定义。
树的遍历方法有前序遍历、中序遍历、后序遍历、层序遍历。平衡二叉树是一种二叉搜索树,每个节点的左右子树高度差不超过1。
手撕代码:判断一棵树是否为平衡二叉树。
可以通过递归计算树的高度,判断每个节点的左右子树高度差是否不超过1。
设计一个通用的日志接口。
可以定义日志级别、日志输出方式(如文件、控制台)、日志格式等接口方法,方便不同的日志实现。
线程池的处理逻辑。
创建一定数量的线程,将任务放入任务队列,线程从队列中取出任务执行,任务执行完后继续从队列取任务。
怎么判断一个线程是否保活。
可以通过线程的返回值、异常捕获、心跳机制等方式判断线程是否保活。
设计一种能处理10万连接的方案,10万连接同时存在。
可以采用异步IO模型(如epoll)、线程池、负载均衡等技术,优化服务器性能和资源管理。
手撕代码:判断一个字符串中,计算有多少子串是回文串。
可以通过中心扩展法或动态规划法遍历字符串,判断每个子串是否为回文串。
如何用 gdb 调试代码
常用步骤包括启动gdb、加载可执行文件、设置断点、运行程序、单步执行、查看变量值等。
检测内存泄漏的软件
如Valgrind、AddressSanitizer等。
申请十个 char 的堆空间,并且释放
使用`new char[10]`申请内存,使用`delete[]`释放内存。
STL 用过的吗?vector 和 list 有什么区别?
vector是动态数组,支持随机访问,插入和删除效率低;list是双向链表,不支持随机访问,插入和删除效率高。
有一个类 students,名字和学号,生成 50 个实例,保存在一个类里面。排序怎么排列?排序,重载。年龄20岁的删除。
可以将students实例存储在容器中,通过重载比较运算符实现排序,遍历容器删除年龄20岁的实例。
设计模式,写一个单例模式。工厂模式,为什么要工厂模式?
单例模式确保一个类只有一个实例,并提供全局访问点。工厂模式用于创建对象,将对象的创建和使用分离,提高代码的可维护性和可扩展性。
汇编语言
汇编语言是一种低级语言,与机器语言一一对应,用于直接操作计算机硬件,如寄存器、内存等。
C++11 新加的语法
如智能指针、lambda表达式、右值引用、范围for循环、auto关键字等。
lambada表达式
一种匿名函数,用于简洁地定义和使用函数对象,常用于回调函数、算法等场景。
多态的实现,虚表及指向虚表指针的存储,类中指向虚表指针的个数,基类指针与子类指针指向同一对象值是否相等,指向虚表的指针是什么完成初始化的?
多态通过虚函数实现,每个包含虚函数的类都有一个虚表,对象中包含一个指向虚表的指针。类中只有一个指向虚表的指针。基类指针和子类指针指向同一对象时,值可能不同。指向虚表的指针在对象构造时完成初始化。
基类指针和子类指针的转换问题,是否了解static_cast及dynamic_cast的底层原理
static_cast用于基本类型转换和有继承关系的指针或引用转换,不进行运行时类型检查;dynamic_cast用于有继承关系的指针或引用的安全转换,会进行运行时类型检查。
类继承时,成员变量和vptr是怎么存储的(好像是问存储顺序)?
一般先存储基类的成员变量,然后是派生类的成员变量,vptr通常存储在对象的起始位置。
shared_ptr如何实现,引用计数如何实现的
shared_ptr通过引用计数实现,多个shared_ptr可以共享同一个对象,引用计数记录有多少个shared_ptr指向该对象。当引用计数为0时,释放对象内存。引用计数通常存储在一个单独的控制块中。
构造函数为什么不能是虚函数,构造函数能不能调用虚函数?
构造函数不能是虚函数,因为虚函数调用依赖于虚表指针,而对象在构造时虚表指针还未初始化。构造函数可以调用虚函数,但调用的是基类的虚函数版本,因为此时派生类部分还未构造。
如何区别大端机和小端机?
可以通过代码检测,如定义一个整数变量,取其地址并访问第一个字节,若第一个字节存储的是整数的高位,则为大端机;若存储的是低位,则为小端机。
STL用过么,讲一下vector,如何扩张?拷贝构造函数和移动构造函数如何选择?
vector扩张时会重新分配更大的内存空间,将原数据拷贝或移动到新空间,然后释放原空间。当对象是可移动的且性能要求较高时,优先选择移动构造函数;否则使用拷贝构造函数。
map用过么?红黑树是绝对平衡二叉树么?什么情况下插入复杂度最坏?
map是基于红黑树实现的关联容器。红黑树不是绝对平衡二叉树,它是一种自平衡二叉搜索树。插入复杂度最坏的情况是插入节点导致树的高度大幅增加,但红黑树通过旋转和变色操作保证插入复杂度为O(log n)。
不用虚函数如何实现多态?
可以通过函数指针、模板等方式实现多态。
C++如何禁止一个类被继承?
可以将类的构造函数和析构函数声明为private或protected,并使用友元类来创建对象;在C++11及以后,也可以使用`final`关键字。
线程的通信方式,同步方式,为什么要进行同步?系统是如何给线程分配一个栈的?
线程通信方式有共享内存、消息队列等;同步方式有互斥锁、信号量、条件变量等。进行同步是为了避免多个线程同时访问共享资源导致的数据不一致问题。系统通常在创建线程时为其分配一个栈空间。
代码:实现一个字符串类; 删除vector中重复的元素(双指针)
实现字符串类需要考虑构造函数、析构函数、拷贝构造函数、赋值运算符等。删除vector中重复元素可以使用双指针法,一个指针用于遍历,另一个指针用于记录不重复元素的位置。
智能指针的实现
以shared_ptr为例,需要实现引用计数、构造函数、析构函数、拷贝构造函数、赋值运算符等。
const用法,define用法,适用场景及缺点
const用于定义常量,确保变量值不被修改;define是预处理指令,用于定义宏。const更安全,有类型检查;define没有类型检查,可能导致意外错误。
new和malloc的区别
new是C++运算符,调用构造函数;malloc是C语言函数,仅分配内存。new返回对象指针,malloc返回void*指针。
C++11 新特性,模板的基本知识
C++11新特性如智能指针、lambda表达式等。模板是C++的泛型编程机制,允许编写通用的代码,通过模板参数实现不同类型的处理。
代码:将一个vector中的所有奇数放前面,所有偶数放后面?(双指针即可)
使用双指针,一个指针从左向右找偶数,另一个指针从右向左找奇数,交换两个指针指向的元素。
C++有没有相应的库可以完成上面的操作(STL中的partition 或者sort+lambda都行)
可以使用STL中的`partition`函数或`sort`函数结合lambda表达式实现。
实现字符串类(怎么总是考这个?)不过和第一次不一样,要写出移动构造函数,重载赋值运算符(两个,一个参数是对象,一个是右值引用)
需要实现构造函数、析构函数、拷贝构造函数、移动构造函数、赋值运算符(拷贝赋值和移动赋值)。
TCP和UDP的区别
TCP面向连接、可靠、基于字节流;UDP无连接、不可靠、基于数据报。
解释三次握手,没有第三次会发生什么
三次握手用于建立TCP连接,客户端向服务器发送SYN包,服务器回复SYN+ACK包,客户端再发送ACK包。没有第三次握手,服务器无法确认客户端是否收到自己的SYN+ACK包,连接无法正常建立。
栈和队列的区别
栈是后进先出(LIFO)的数据结构,队列是先进先出(FIFO)的数据结构。
哈希表原理
哈希表通过哈希函数将键映射到存储位置,使用数组存储数据。当发生哈希冲突时,采用开放寻址法或链地址法解决。
哈希冲突,详细介绍解决方法
解决哈希冲突的方法有开放寻址法(线性探测、二次探测等)、链地址法(每个存储位置使用链表存储冲突元素)、再哈希法等。
线程和进程区别,关于进程的代码场景题
进程是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位;线程是进程中的一个执行单元。进程拥有自己独立的内存空间和系统资源,线程共享进程的资源。
进程间的通信方式
有管道、命名管道、消息队列、共享内存、信号量等。
锁的种类,关于锁的代码场景题
常见锁有互斥锁、读写锁、自旋锁等。根据具体代码场景选择合适的锁,避免死锁和性能问题。
单核系统和多核系统
单核系统只有一个CPU核心,同一时间只能执行一个线程;多核系统有多个CPU核心,可以同时执行多个线程,提高并发性能。
malloc不释放内存会怎么样
会导致内存泄漏,可用内存逐渐减少,可能影响系统性能和稳定性。
介绍下指针,野指针会造成什么
指针是存储内存地址的变量。野指针是指向无效内存的指针,使用野指针可能导致程序崩溃、数据错误等问题。
static 关键字、全局static作用范围、局部static生命周期
static关键字用于修饰变量和函数。全局static变量作用范围限于当前文件,局部static变量生命周期从第一次初始化到程序结束。
两个对象能不能直接==比较?为什么?应该怎么做?
默认情况下,对象直接使用==比较的是对象的地址。如果要比较对象的内容,需要重载==运算符。
重载
函数重载是指在同一作用域内,允许存在多个同名函数,但参数列表不同。运算符重载是对已有的运算符赋予新的功能。
strlen和sizeof
strlen是函数,用于计算字符串的实际长度(不包括字符串结束符);sizeof是运算符,用于计算数据类型或变量占用的内存字节数。
常用STL容器的特点,底层
如vector基于动态数组,支持随机访问;list基于双向链表,插入和删除效率高;map基于红黑树,可按键排序;unordered_map基于哈希表,查找效率高。
红黑树
是一种自平衡二叉搜索树,通过颜色标记节点,保证树的高度平衡,插入、删除、查找操作的时间复杂度为O(log n)。
多态
多态是指同一操作作用于不同的对象,可以有不同的行为。通过虚函数和继承实现运行时多态。
虚指针、虚表
虚指针是对象中指向虚表的指针,虚表是一个存储虚函数地址的数组。包含虚函数的类都有一个虚表,对象通过虚指针找到虚表,从而调用正确的虚函数。
new、delete、malloc、free
new和delete是C++的运算符,用于对象的动态分配和释放,会调用构造函数和析构函数;malloc和free是C语言的函数,仅进行内存的分配和释放。
TCP和UDP
TCP面向连接、可靠、基于字节流;UDP无连接、不可靠、基于数据报。TCP适用于对数据准确性要求高的场景,UDP适用于对实时性要求高的场景。
死锁
死锁是指多个进程或线程因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。产生死锁的四个必要条件是互斥条件、请求和保持条件、不剥夺条件、环路等待条件。
多线程如何避免竞争
可以使用互斥锁、信号量、原子操作等同步机制,合理设计线程间的通信和协作方式,避免多个线程同时访问共享资源。
MySQL索引
索引是一种数据结构,用于提高数据库查询效率。常见的索引类型有B树索引、哈希索引等。合理使用索引可以加快查询速度,但过多的索引会影响插入、更新和删除操作的性能。
Redis数据持久化
Redis支持RDB(快照)和AOF(追加日志)两种持久化方式。RDB是将某个时间点的数据库状态保存到磁盘,AOF是将Redis执行的写命令追加到文件中。
快排
快排(快速排序)是一种分治算法,选择一个基准值(pivot),将数组分为两部分,小于基准值的元素放在左边,大于的放在右边,然后递归地对两部分进行排序。平均时间复杂度为O(n log n),最坏为O(n²)。优化方法包括随机选择基准值、三数取中法等。
TCP超时重传
TCP超时重传是保证数据可靠性的机制。发送方在发出数据后启动定时器,若在超时时间内未收到确认(ACK),则重传该数据。超时时间通常基于往返时间(RTT)动态计算。重传策略包括超时重传和快速重传(收到三个重复ACK时立即重传)。
动态链接库和静态链接库
静态链接库(.a/.lib)在编译时被完整复制到可执行文件中,运行时无需依赖外部文件;动态链接库(.so/.dll)在运行时动态加载,多个程序可共享同一库文件,节省内存。动态链接库支持运行时更新,缺点是依赖环境;静态链接库的优点是独立性强,缺点是文件体积大。
内存泄漏
内存泄漏指程序中已分配的内存由于某种原因无法被释放,导致可用内存逐渐减少。常见原因包括动态分配内存后未释放(如C++中new后未delete)、资源未关闭(如文件句柄、网络连接)、循环引用(如shared_ptr导致的循环)。检测工具包括Valgrind、AddressSanitizer等。
B树
B树是一种自平衡的多路搜索树,每个节点可以有多个子节点。特点是所有叶子节点在同一层,能保持树的高度平衡,适用于文件系统和数据库索引。插入、删除、查找操作的时间复杂度均为O(log n)。B+树是B树的变种,非叶子节点只存储索引,数据全部存储在叶子节点,更适合范围查询。
内存越界
内存越界指程序访问了不属于它的内存区域,常见于数组越界、指针越界等。例如,访问数组时索引超出范围,或使用野指针。内存越界可能导致程序崩溃、数据错误、安全漏洞(如缓冲区溢出攻击)。预防方法包括边界检查、使用安全的API、智能指针等。