作者:Buffer_专心找工版
链接: https://www.nowcoder.com/feed/main/detail/b5d88bf57f7a4a8695b95167cf75dcb4?sourceSSR=search


1.指针和引用

指针是一个变量,其存储的是另一个变量的内存地址。通过指针,你可以间接访问和修改存储在这个地址上的数据。

引用是另一个变量的别名,一旦引用被初始化后,就无法更改引用的对象。引用必须在定义时被初始化。

特性

指针

引用

是否可以为空

可以为 nullptr

不可以为空,必须绑定到有效对象

是否可以重新绑定

可以在任何时候指向另一个对象

绑定后不可改变

是否可以进行运算

可以进行加减运算,用于数组遍历或指针偏移

不能进行运算

语法复杂性

需要解引用操作符 * 和取地址操作符 &

语法更简洁,类似直接访问变量

使用场景

动态内存管理、数组操作、函数指针

函数参数传递、返回值优化

2.关键字 static、volatile

static 关键字

  • 静态局部变量:当 static 变量在函数内声明时,它的生命周期会超出函数的范围,变量只会被初始化一次,并且在多次调用该函数时保持其值。
  • 静态成员变量:当 static 变量在类内声明时,它属于类而不是类的实例。所有该类的对象共享这一个变量。需要在类外定义和初始化。
  • 静态成员函数:静态函数属于类而不是类的实例,不能访问非静态成员变量。它可以通过类名直接调用,不需要创建对象。
  • 静态全局变量和函数:在全局作用域中,static 限定符限制变量或函数的作用域仅在声明它的文件中,使其具有内部链接属性。

volatile 关键字

volatile 关键字用于声明一个变量可能会被意外地改变,通常由硬件或其他线程修改,因此编译器不应对其进行优化。

特性

static

volatile

目的

控制变量或函数的生命周期与作用域

防止编译器优化,保证每次访问都读取内存

使用场景

全局变量、类成员、局部变量、函数等

多线程访问变量、硬件寄存器访问

生命周期

影响变量的生命周期(如静态局部变量)

不影响生命周期,只影响编译器优化行为

作用

变量初始化一次,保持函数调用间的变量状态

保证变量的值随时从内存读取,避免缓存

多线程

不直接用于线程安全

可以用于多线程编程中确保内存可见性

优化

不影响编译器优化

禁止编译器优化对该变量的存储

3.宏定义和内联函数比较

特性

宏定义 (Macro)

内联函数 (Inline Function)

替换机制

纯文本替换

编译器决定是否展开为内联

类型检查

无类型检查

有类型检查,遵循C++函数的规则

作用域

无作用域,影响整个文件

遵循C++作用域规则,局部有效

调试

难以调试,无法设置断点

易于调试,支持断点和调试信息

错误处理

容易引入难以察觉的错误,如优先级问题

具有类型和范围检查,减少潜在错误

代码膨胀

可能导致代码膨胀

大量调用可能导致膨胀,但编译器会优化

使用场景

常用于定义常量、简单的代码替换

用于小型、频繁调用的函数,提高效率

4.多态的实现方式

实现方式

描述

关键特性

编译时多态

在编译时决定调用哪个函数或操作符。

静态绑定(Static Binding)

函数重载

同一个函数名可以有不同的参数列表。

根据参数类型和数量选择合适的函数。

运算符重载

为用户定义的类型提供操作符的不同实现。

允许自定义类型像内置类型一样使用操作符。

模板重载

使用模板参数来创建多态行为。

泛型编程,通过模板参数进行多态。

运行时多态

在运行时决定调用哪个函数或操作。

动态绑定(Dynamic Binding)

虚函数

基类中声明为 virtual 的函数,在派生类中可以被重写。

通过基类指针或引用调用派生类的实现。

5.内存管理

6.如何实现线程安全的队列

  • 互斥锁和条件变量
  • 原子操作
  • 消息队列

7.哈希表原理,设计思路

哈希表是一种基于 键值对 存储的数据结构。它通过 哈希函数 将键(Key)映射到数组中的一个位置(索引),从而实现快速的数据插入、删除和查找操作。

设计一个哈希函数,将键转换为数组的索引值。这个函数应该尽量将不同的键均匀分布到数组的不同位置,减少冲突。

8.用过哪些设计模式 - 实现、使用场景

算法题

- 旋转数组查找
  • 利用旋转数组的特性,改进二分查找算法。
  • 直接遍历数组寻找目标值。
  • 先找到数组的旋转点(最小值),然后分别对旋转点左侧和右侧的两个有序子数组进行二分查找。
- 奇偶分离,需要保证相对顺序

排序算法

10.单核 CPU 上运行多线程程序需要加锁吗

需要加锁。不加锁可能导致逻辑错误和数据不一致。

11.进程、线程、协程对比

特性

进程

线程

协程

定义

程序的执行实例,拥有独立的地址空间。

进程中的执行单元,分享进程的地址空间。

轻量级的执行单元,通常由用户态库管理。

资源占用

每个进程拥有独立的资源,如内存、文件描述符等。

线程共享进程的资源,资源占用比进程少。

协程共享线程的资源,占用最小。

创建与销毁

创建和销毁开销较大。

创建和销毁开销较小。

创建和销毁开销最小。

调度

由操作系统内核进行调度。

由操作系统内核进行调度。

由用户态库进行调度,通常不涉及内核调度。

上下文切换

上下文切换开销较大(涉及内核态和用户态)。

上下文切换开销较小(不涉及内核态)。

上下文切换开销最小(在用户态进行)。

并发性

支持多进程并发执行。

支持多线程并发执行。

支持高效的协作式并发执行。

通信

进程间通信(IPC)复杂。

线程间通信相对简单(共享内存、信号量等)。

协程通常通过函数调用或共享变量进行通信。

同步

需要进程间同步机制。

需要线程同步机制(如互斥锁、条件变量)。

通过协程的调度和状态管理进行同步。

应用场景

适用于需要完全隔离的任务。

适用于需要共享资源的任务。

适用于高效的协作式任务处理,通常在单线程中。

12.Linux 网络 IO 模型

  • 阻塞 I/O: 简单但效率低。
  • 非阻塞 I/O: 线程可以继续执行其他任务,但可能会进行轮询。
  • I/O 多路复用: 高效处理大量并发连接,epoll 在 Linux 中表现优异。
  • 信号驱动 I/O: 避免轮询,但实现复杂。
  • 异步 I/O: 高效,适用于高并发应用,但实现复杂。

13.Redis数据结构、高效的原因、持久化的方式

  • 数据结构: Redis 提供了多种高效的数据结构,包括字符串、哈希、列表、集合、有序集合、位图、HyperLogLog 和地理空间。
  • 高效原因: 内存存储(在内存中操作,读写速度非常快。)、高效数据结构(使用高效的底层数据结构)、单线程模型(避免了线程上下文切换的开销)、I/O 多路复用和简单协议使 Redis 高效。
  • 持久化方式: RDB 快照、AOF 日志和 RDB + AOF 组合提供了不同的持久化选项。

14.MySQL主键索引和唯一索引

特性

主键索引(Primary Key Index)

唯一索引(Unique Index)

唯一性

强制唯一性,不允许重复值和 NULL。

强制唯一性,但允许 NULL 值。

自动生成

默认自动创建(如果未指定主键,InnoDB 会自动生成一个隐藏的聚簇索引)。

需要显式创建。

用途

标识表中的唯一记录,并用于表间的关系(如外键)。

用于保证某列或多列的值唯一。

数量限制

每个表只能有一个主键索引。

每个表可以有多个唯一索引。

聚簇索引

是聚簇索引,表中的数据按主键索引组织和存储。

可以是非聚簇索引,数据存储与索引分离。

外键约束

可以作为外键的参照字段。

不能作为外键的参照字段。

性能影响

插入和更新时有较大开销,因为必须保持数据有序。

插入和更新时有一定开销,但通常比主键索引小。

默认行为

如果不指定,则通常会使用主键索引进行查询。

如果查询涉及唯一约束的列,可能会使用唯一索引。

15.MySQL事务隔离级别,是否解决了不可重复读和幻读,什么情况下会幻读

隔离级别

不可重复读

幻读

幻读发生情况

读未提交

未解决

未解决

任何时候都可能发生,事务可以读取到其他未提交事务的数据。

读已提交

解决

未解决

另一事务在当前事务查询后插入或删除数据,再次查询时发生。

可重复读

解决

解决(MySQL InnoDB 中)

MySQL InnoDB 使用间隙锁防止幻读,否则可能发生。

可串行化

解决

解决

隔离最严格,不会发生幻读,事务按顺序串行执行。

算法题 - 1-100 个数组成的数组,现在随机删除了一个数,请找出这个数 - 复杂度 - 有序情况怎么做,复杂度

微信实习

- 推荐链路 - 做哪方面开发 - 可用性和稳定性 - 做了哪些保障,尽可能讲 - 兜底策略 - 服务降级 - 存储用什么组件

18.实现一个订单匹配系统,怎么做

算法题:实现 geohash 编码

  • 有什么作用
  • 位置编码和检索

20.读过哪些中间件源码

C++后端八股文