2024最新大厂C++面试真题合集,大厂面试百日冲刺 day7

腾讯CSIG腾讯云客户端开发

拥塞控制、流量控制、重传条件有了解吗?

  • 拥塞控制:拥塞控制旨在避免网络中的过载情况。TCP协议中的拥塞控制通过算法(如慢启动、拥塞避免、快重传、快恢复等)动态调整数据包发送速率,以减少网络中的拥塞。
  • 流量控制:流量控制是为防止发送方快速发数据而接收方来不及接收而设计的。TCP使用滑动窗口机制作为流量控制的一种实现,确保发送方不会溢出接收方的缓冲区。
  • 重传条件:在通信过程中,当数据包丢失、损坏或确认应答超时时,需要进行重传。TCP协议使用ACK机制和超时计时器来确定何时需要重传数据包。例如,快速重传是在接收到三个冗余ACK时触发的一种机制,而正常的超时重传则是在数据包发送后经过一段时间仍未收到ACK时触发

在.h文件中直接实现类能否成功运行?这样写的缺点是什么?

在 .h 文件中直接实现类是可以成功运行的。
缺点:

  1. 编译时间增加:每次包含这个头文件的源文件被编译时,都会重新编译类的实现,增加编译时间。
  2. 代码可维护性降低:将声明和实现混在一起,使得代码结构不清晰,降低了代码的可读性和可维护
    性。
  3. 可能导致链接错误:如果同一个类的实现在多个源文件中被包含,可能会导致链接器发现多个相同
    符号的定义,从而导致链接错误。

虚函数的作用、实现机制

作用:
C++虚函数的主要作用是允许在派生类中对基类的方法进行重写,以实现运行时多态。通过虚函数,可以通过基类指针或引用来调用派生类的函数。

实现机制:
虚函数是通过虚函数表(vtable)实现的。每一个含有虚函数的类都有一个对应的虚函数表;这个表是一个函数指针数组,指向类的动态绑定的虚函数。类的每个对象都包含一个指向这个表的指针
(vptr)。当调用一个虚函数时,实际上是通过vptr来查询vtable,然后通过vtable来动态绑定到对应的函数实现。这个机制在运行时完成,允许多态行为发生。

讲讲虚函数表?什么时候创建?

虚函数表是一个存储虚函数地址的指针数组,每个具有虚函数的类都有自己的虚函数表。虚函数表在编译时创建,为每个类生成一个,在程序运行时,每当创建一个对象时,该对象会包含一个指向对应虚函数表的指针(通常称为vptr)。当类被实例化为对象时,vptr初始化指向类的虚函数表。如果有派生类重写了基类的虚函数,派生类的虚函数表中会用新的函数地址覆盖基类函数的地址。这样,即使通过基类指针调用虚函数,也能执行到派生类中对应重写的虚函数,实现多态。

具体场景中父类子类虚函数调用顺序

父类和子类中虚函数的调用顺序依赖于对虚函数的调用环境。

  • 创建对象时:首先调用构造函数。如果在构造函数中调用虚函数,则调用的是当前构造阶段类的版本,而不是子类重写后的版本。这是因为在基类构造期间,子类部分尚未初始化,因此不能调用子类中的重写版本。
  • 通过基类的指针或引用调用虚函数时:如果子类重写了这个虚函数,那么即便是通过指向基类的指针或引用调用,实际执行的也是子类中重写的版本。这是多态的体现。
  • 在析构时:析构的顺序与构造相反,首先调用派生类的析构函数,然后调用基类的析构函数。如果在析构函数中调用虚函数,和构造函数时相同,调用的是该阶段对应类的虚函数版本。

为什么智能指针能自动释放内存?底层是怎么实现的?

智能指针能够自动释放内存,主要是因为它们内部实现了资源管理和所有权语义。智能指针如
std::unique_ptr 和 std::shared_ptr 通过构造函数和析构函数,以及复制控制函数(拷贝构造函
数、移动构造函数、拷贝赋值运算符、移动赋值运算符)来管理资源。

  • std::unique_ptr :通过所有权模型实现。每个 unique_ptr 都独占它指向的资源。当unique_ptr 被销毁(例如离开作用域)时,它的析构函数会自动释放其所拥有的资源。
  • std::shared_ptr :内部使用一个引用计数机制。每次一个 shared_ptr 拷贝构造或赋值给另一个 shared_ptr 时,内部的引用计数会增加。当引用计数降至0(即没有 shared_ptr 指向资源时),析构函数会被调用以释放资源。

map和unordered_map区别,使用场景

map (通常实现为红黑树)和 unordered_map (基于哈希表)是C++标准库中的两种关联容器,它们的
主要区别如下:

  1. 内部组织:
  • map 是有序的,根据键值自动排序。
  • unordered_map 是无序的,不排序。
  1. 性能:
  • map 的查找、插入和删除操作的时间复杂度大致为O(log n)。
  • unordered_map 的平均情况下查找、插入和删除的时间复杂度为O(1),最坏情况为O(n)(冲突严重时)。
  1. 内存消耗:
  • map 通常消耗更多的内存,因为需要维护额外的排序信息。
  • unordered_map 内存消耗相对较少。
  1. 使用场景:
  • 当你需要保持元素有序时使用 map 。
  • 当你不需要排序但希望得到更好的性能时使用 unordered_map 。

map、unordered_map底层实现,查询插入删除复杂度对比

map 和 unordered_map 是C++中的两种关联容器,它们的底层实现以及对应操作的时间复杂度如下:
map :

  • 底层实现:通常用平衡的二叉搜索树(通常为红黑树)实现。
  • 查询:时间复杂度为O(log n),因为它需要在二叉搜索树中查找元素。
  • 插入和删除:时间复杂度为O(log n),因为操作可能需要重新平衡树结构。

unordered_map :

  • 底层实现:通常用哈希表实现。
  • 查询:平均情况是O(1),在哈希冲突严重时最坏的情况是O(n)。
  • 插入和删除:平均情况是O(1),最坏情况是O(n)。

讲讲红黑树特性?插入结点流程?

红黑树是一种自平衡的二叉搜索树,具有以下五个基本特性:

  1. 节点颜色:每个节点要么是红色,要么是黑色。
  2. 根节点特性:根节点总是黑色的。
  3. 红色节点特性:红色节点的子节点必须是黑色的(即红色节点不能相连)。
  4. 黑色高度特性:从任一节点到其每个叶子节点的所有路径上,黑色节点的数目都相同。
  5. 叶子节点特性:所有叶子节点(NIL节点,树末端的空节点)都是黑色的。

插入结点流程主要包含以下几个步骤:

  1. 创建节点:新插入的节点默认为红色。
  2. 正常插入:像在普通二叉搜索树中一样插入节点。
  3. 修复红黑树性质
    :通过一系列的树旋转和重新着色来恢复红黑树的特性。这步可能包含以下几种情况:
    • 情况1(父节点是黑色):不违背红黑树的性质,不需要额外操作。
    • 情况2(父节点和叔叔节点都是红色):通过改变父节点、叔叔节点和祖父节点的颜色来解决。
    • 情况3(父节点是红色且叔叔节点是黑色或缺失,并且新节点位于父节点的内侧):进行一次或两次树旋转和重新着色。
    • 情况4(父节点是红色且叔叔节点是黑色或缺失,并且新节点位于父节点的外侧):通过树旋
      转和更改颜色来解决。

两个进程同时操作全局变量i++,最后i的值可能是多少?为什么?

i++ 并非原子操作,实际包含了 读取 , 增加 , 存储 三个操作。在多进程环境下,如果两个进程几乎同时进行 i++ 操作,可能会出现竞态条件(Race Condition),即两个进程读取了同一个值,接着各自增加1,最后存回内存。假设i初始为0,理想情况下,两次 i++ 后i应为2,但在上述竞态条件下,可能最后i的值仍为1,因为两个进程读取和存储的都是同一个旧值。

鼎甲科技C++

std::move 一个 const 对象有什么后果?

尝试 std::move 一个 const 对象的结果,通常会退化到使用拷贝构造或拷贝赋值,就像没有使用 std::move 一样。

std::move 一个 const 对象实际上不会移动该对象。std::move 本身只是将对象的类型转换为右值引用,使得可以使用移动语义。但是,如果对象是 const,即便转换为右值引用,依然会被视为 const T&& 类型,这意味着移动构造函数或移动赋值操作符无法应用于这个对象,因为它们通常要修改源对象,而 const 属性禁止修改。

不考虑合理性的话,如果要move一个const对象的话怎么办?

如果必须 “移动” const 对象,可以通过将 const 修饰符强制性地从该对象中移除来实现,方法是使用 const_cast。但需要注意,这样做会违反 const 的语义,可能会引发未定义的行为。

使用make_shared构造shared_ptr和先new再置入哪个好?好在哪?

使用 std::make_shared 构造 std::shared_ptr 通常更好。

  1. 效率std::make_shared 在单个操作中分配内存,同时为对象和其引用计数分配空间,减少了一次内存分配和释放的开销。
  2. 异常安全:使用 new 后再置入 shared_ptr 在构造过程中可能因为异常导致内存泄露,而 std::make_shared 避免了这个问题,因为它只有一个操作。
  3. 代码简洁std::make_shared 能以更简洁的代码完成同样的工作。

make_shared实现了解吗?

std::make_shared 的实现主要包含以下步骤:

  1. 分配一块足够大的内存,用来存储对象本身和控制块(包括引用计数和弱引用计数)。
  2. 在分配得到的内存上构造对象,构造控制块。
  3. 返回指向新构造对象的 std::shared_ptr

多进程模型和多线程模型的优缺点?

多进程模型优点:

  1. 隔离性:进程间内存、资源相互隔离,互不影响,提高了程序稳定性。
  2. 安全性:由于隔离性,进程间不会相互影响,避免了数据竞争和其他安全问题。
  3. 利用多核:进程可以分布到不同的CPU核心,利用多核优势。

多进程模型缺点:

  1. 资源消耗:每个进程都有独立的内存和资源,占用的系统资源多。
  2. 上下文切换:进程切换开销相对较大。
  3. 通信成本:进程间通信(IPC)比线程间通信复杂且成本较高。

多线程模型优点:

  1. 资源共享:线程共享进程资源,易于通信和数据共享。
  2. 创建销毁快:线程的创建和销毁比进程更快,资源开销小。
  3. 上下文切换快:线程上下文切换比进程快,开销小。

多线程模型缺点:

  1. 稳定性差:一个线程崩溃可能导致整个进程崩溃。
  2. 安全问题:线程间共享内存容易造成竞态条件,需要同步机制。
  3. 受限于单个进程:所有线程运行在同一个进程中,受限于该进程的资源限制和策略。

为什么选择MongoDB存离线消息?

选择MongoDB存储离线消息的原因包括:

  1. 文档导向:MongoDB是一种文档型数据库,适合存储结构化或半结构化的数据,如JSON格式的消息。
  2. 高性能:MongoDB提供高速读写能力,适合快速存取大量离线消息。
  3. 可扩展性:MongoDB易于水平扩展,当消息量增加时可以通过增加更多节点来提升处理能力。
  4. 灵活的查询:MongoDB支持复杂的查询操作,便于实现各种消息检索和过滤需求。
  5. 高可用性:MongoDB的复制集特性可以提供数据的高可用性和灾难恢复。

了解 MySQL、LevelDB 底层存储原理吗?

MySQL:
MySQL主要使用B+树作为其底层存储结构,特别是在InnoDB存储引擎中。B+树是一种平衡树,能够保持数据排序,优化了读写操作和磁盘I/O性能。其主要特点是所有的数据都存储在叶子节点上,非叶子节点只存储键值信息,这种结构使得范围查询变得十分高效。

LevelDB:
LevelDB使用LSM树(Log-Structured Merge-Tree)作为其底层数据结构。LSM树通过将写入操作首先存储在内存中的写缓冲区(MemTable)中,然后异步批量写入硬盘上的SSTable(Sorted Strings Table)文件,来优化写性能。为了保持数据查询的效率,LevelDB会定期进行压缩和合并操作,以减少存储占用和提高读取性能。

如何理解移动语义的?移动一个int会不会将其置0?

移动语义是C++11引入的一个特性,旨在优化资源管理和提高性能。通过移动语义,可以将一个对象的资源(如动态分配的内存)直接转移给另一个对象,而无需复制。这是通过定义移动构造函数和移动赋值操作符实现的。移动操作后,原对象不再拥有这些资源,其状态变为未定义(但必须保持对象处于合法状态以便进行销毁)。

对于基本数据类型,如int,实际上不存在“移动”的操作。int是一个简单的值类型,不涉及动态资源管理。移动一个int和复制它效果相同,都是简单的值复制。移动操作不会改变原始int值,也就是说,移动一个int并不会将其置为0。移动语义主要针对那些管理动态资源的复杂对象,对于简单的值类型并没有意义。

auto_ptr为什么被淘汰?

auto_ptr被淘汰的主要原因在于其所有权转移的语义。当你将一个auto_ptr赋值给另一个auto_ptr时,源auto_ptr会失去对对象的所有权,也就意味着它不再指向该对象。这造成了潜在的危险,因为程序员可能会尝试访问一个已经不再拥有的对象,从而导致未定义的行为。

而C++11后引入了unique_ptr,它在所有权管理上提供了更安全的处理方式。unique_ptr不支持复制操作,因此不会出现所有权不明确的情况。

此外,auto_ptr在C++标准库的容器中不能正常工作,因为容器的语义需要能够复制和赋值元素,而auto_ptr的所有权转移语义并不满足这个要求。

结构体和类区别

结构体(struct)和类(class)之间的主要区别在于默认访问控制和默认继承权限:

  1. 默认访问控制struct的成员默认为public,而class的成员默认为private
  2. 默认继承权限struct继承默认为public继承,而class继承默认为private继承。

如何禁止拷贝语义?C++11之前怎么做?

为了禁止拷贝语义,你需要删除类的拷贝构造函数和拷贝赋值操作符。

在C++11之前,通常的做法是将拷贝构造函数和拷贝赋值操作符声明为私有,并且不提供它们的实现。这样当尝试进行拷贝操作时,编译器会因为访问私有成员而报错。

从一个函数中返回一个const char* 类型的 “hello world”字符串有几种方法?

  1. 返回字面量字符串: 字面量字符串在静态存储区域,它的生命周期跨越整个程序,因此可以安全地返回。
  2. 返回静态局部变量: 静态局部变量在函数调用结束后仍然存在,因此可以安全地返回。但这种方式只能用于简单的字符串,不能用于动态创建或修改的字符串。

能不能定义一个std::string("helloworld")再返回其 c_str()?

不可以。这是因为当你创建一个局部的std::string对象并从函数中返回其c_str()时,std::string对象在函数返回后会被销毁,它的析构函数会释放其占用的内存。这将导致返回的const char*指针指向一块已经被释放的内存,从而产生悬挂指针和未定义行为。

如何理解异常安全的?

异常安全是指代码在面临异常情况时,能够保证程序的完整性,防止异常导致程序状态被破坏。通常将异常安全性分成三个等级:

  • 基本异常安全:如果因为异常而退出操作,程序状态依然保持内部一致性。资源不泄露,不会有数据被破坏。
  • 强异常安全:如果操作由于异常而失败,在异常抛出后,程序状态保持不变,就像从未发生过那样。
  • 无异常安全:即便操作抛出异常,仍可以保持程序的正确性。例如,不抛出异常,而是返回错误码。

STL中哪些容器是链表实现的?

在C++ STL中,使用链表实现的容器是std::liststd::forward_list。其中std::list是双向链表,std::forward_list是单向链表。

单链表如何删除当前节点?不从头遍历如何删除?

在单链表中,如果不从头遍历且只有当前节点的指针,通常的方法是将当前节点的下一个节点的数据复制到当前节点,然后删除当前节点的下一个节点。这种方法不适用于删除最后一个节点,因为它没有下一个节点的数据可以复制。如果需要删除的是最后一个节点,这种方法将失效,通常需要从头遍历来定位前一个节点来进行删除。

mmap 用过吗?原理是什么?

mmap()是一种内存映射的技术,它将文件或其他对象映射到进程的地址空间中,这样进程可以像访问内存一样直接访问这个对象。当进程访问这块内存区域时,实际上是在访问映射的文件或对象,无需再使用read和write等系统调用。mmap()提高了文件访问的效率,因为避免了数据的拷贝操作。

在内部工作原理上,mmap()会创建一个新的虚拟内存区域,然后将这段内存区域与被映射的文件关联起来。而操作系统负责管理虚拟内存和物理内存之间的映射关系,只有当访问到这段内存时,操作系统会将对应的文件数据加载到物理内存中(惰性加载)。这种方式不仅节约了内存资源,还能更高效地处理大文件,因为不需要一次性将整个文件加载到内存中。

mmap相比传统IO的区别?

mmap相比传统IO(比如read/write系统调用)的主要区别在于:

  1. 数据访问方式:mmap通过将文件映射到进程的地址空间,使得进程可以直接通过内存操作来访问文件数据,无需经过read/write调用;而传统IO需要通过系统调用来读写文件数据到缓冲区中。
  2. 性能:mmap能减少数据在用户空间和内核空间之间的拷贝,对于频繁访问的数据,可以提高效率。而传统IO在每次读写操作时都会有数据拷贝的开销。
  3. 适用场景:mmap适合处理大文件和频繁访问的场景,因为它避免了数据拷贝,并且可以实现文件的惰性加载。传统IO更适合处理顺序读写和对数据拷贝开销不敏感的场景。

mmap是否一定比传统IO更好呢?

不一定。mmap的性能优势依赖于具体使用场景。它适合处理大文件和频繁随机访问的情况,因为可以减少数据拷贝,提高数据访问效率。但对于顺序访问小文件,传统IO(如read/write)可能更高效,因为mmap的初始化和维护映射可能带来额外开销。此外,mmap使用虚拟内存,对于资源受限的环境可能不是最佳选择。

动态库、静态库区别?

动态库(Dynamic Libraries)和静态库(Static Libraries)的区别主要在于:

  1. 链接时机
    • 静态库在编译链接阶段被拷贝到可执行文件中,一旦链接完成,静态库的代码就被集成到了程序中。
    • 动态库在程序运行时被加载到内存中,由操作系统进行管理,不同的程序可以共享同一份动态库的副本。
  2. 文件大小
    • 静态库被整合进可执行文件,使得最终的程序文件更大。
    • 动态库不包含在程序文件中,所以程序文件较小。
  3. 运行时开销
    • 静态链接的程序启动时无需加载额外的库,可以更快地开始执行。
    • 动态库需要在程序启动或运行时进行加载,这可能带来额外的时间开销。

如何查看程序链接的动态库?

在Linux系统中,可以使用ldd命令查看程序链接的动态库。使用方法如下:

ldd /path/to/your/program

这将列出程序依赖的所有动态库及其路径。

如何更改动态链接器查找库的目录?

更改动态链接器查找库的目录可以通过以下方法:

使用LD_LIBRARY_PATH环境变量增加搜索路径:

   export LD_LIBRARY_PATH=/new/library/path:$LD_LIBRARY_PATH

修改/etc/ld.so.conf文件,添加新的库路径,然后运行ldconfig更新缓存。

在编译时通过-rpath链接选项指定库的搜索路径。

如何查看一个进程的所有环境变量?

要查看一个进程的所有环境变量,可以使用cat命令配合进程的环境变量文件,路径通常是/proc/[pid]/environ,其中[pid]是进程ID。

kill命令的本质是在干什么?

kill命令的本质是向指定的进程发送信号。这些信号可以是任何类型,不一定是终止进程。

说一下Linux启动的过程

Linux启动过程大致分为以下步骤:

  1. BIOS/UEFI:计算机加电后,BIOS(基本输入输出系统)或UEFI(统一可扩展固件接口)被激活,进行硬件自检并选择启动设备。
  2. 引导加载器(Bootloader):BIOS/UEFI会加载引导加载器(如GRUB),它允许用户选择不同的操作系统或不同的内核配置。
  3. 内核加载:引导加载器加载Linux内核到内存,并传递必要的启动参数。
  4. 初始化阶段(init):内核初始化硬件设备,挂载根文件系统为只读,并启动第一个用户态程序init(或systemd),这是系统的第一个进程,PID为1。
  5. 用户空间启动:initsystemd根据配置(如/etc/inittabsystemd单元文件)启动系统服务和登录终端。
  6. 登录界面:完成上述步骤后,系统准备就绪,显示登录提示符或图形登录界面,等待用户登录。

Linux内核保存在哪个目录中了解吗?

Linux内核通常保存在/boot目录中,以vmlinuzvmlinux为文件名前缀。

分别说一下服务器客户端网络编程基本流程

服务器客户端网络编程的基本流程如下:

服务器端:

  1. 创建套接字(socket)
  2. 绑定套接字到一个地址和端口(bind)
  3. 开始监听连接(listen)
  4. 接受连接请求,建立连接(accept)
  5. 接收和发送数据(recv/send)
  6. 关闭连接(close)

客户端:

  1. 创建套接字(socket)
  2. 发起连接请求到服务器的地址和端口(connect)
  3. 发送和接收数据(send/recv)
  4. 关闭连接(close)

服务端bind全0地址表示什么?

服务端在bind操作中使用全0地址(例如,IP地址为0.0.0.0)表示绑定套接字到所有可用的网络接口,这样服务器就可以接受针对主机的任意IP地址的连接请求。

客户端程序可不可以bind,有何意义?

客户端程序也可以使用bind操作,这样做可以指定客户端用于出口通信的本地IP地址和端口号。这在客户端机器拥有多个网络接口或者需要使用特定的端口进行通信时有意义。

腾讯c++后台开发

http长连接,短连接什么区别,长连接有什么好处?

HTTP短连接与长连接的区别:

短连接:每次HTTP请求处理完后,建立的TCP连接就会立即关闭,下一个HTTP请求需要重建TCP连接。

长连接(HTTP Keep-Alive):一次TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。

长连接的好处:

  • 减少重复建立连接的时间和资源消耗。
  • 提高数据传输效率。
  • 减少了因频繁建立连接而带来的网络拥塞。

连接中,服务器重启会发生什么?

在TCP连接中,如果服务器突然重启,对于客户端来说会出现以下情况:

  1. 如果客户端正尝试发送数据包,就会由于没有接收到服务器的确认数据包(ACK)而进行超时重传,直到超过规定的尝试次数后,连接会被断开,客户端软件通常在这个时候收到一个错误通知。
  2. 如果客户端没有发送数据,也没有等待接收数据,一般不会立刻发现连接已中断。直到下一次尝试发送数据才会发现连接的异常。

reactor ,proactor的区别?

Reactor 和 Proactor 是两种事件处理模式,用于处理I/O操作以提高应用程序性能。

Reactor模式:同步I/O模型,处理程序(handler)等待事件发生并响应。它通常利用多路复用技术如select/poll,使单个线程能够监听多个I/O请求,当I/O准备就绪时通知相应的处理程序。

Proactor模式:异步I/O模型,处理程序发起操作并立即返回,继续执行其他任务。当I/O操作完成时,系统会通知相应的完成处理程序(completion handler)。这个模型通常依靠操作系统底层的异步I/O机制来实现。

管线化是什么?

管线化是一种技术,在这种技术中,处理器在完成前一个指令的处理之前就开始执行下一个指令的某些阶段。在网络中,它指的是在等待前一请求的完整响应之前发送多个请求,这样可以减少响应时间并提高性能。

linux cp 系统发生了什么?

使用cp命令时,Linux 操作系统执行以下步骤:

  1. 解析命令行参数,确定源文件和目标位置。
  2. 使用系统调用打开源文件和目标文件(如果目标文件不存在,则创建)。
  3. 读取源文件内容并将这些内容写入目标文件(可能涉及多次读/写操作)。
  4. 设置目标文件的权限和所有权(可能从源文件复制)。
  5. 关闭源文件和目标文件的文件描述符。

软链接和cp的区别?

软链接(符号链接)是一个特殊类型的文件,它包含了另一个文件的路径引用,相当于文件的快捷方式。使用软链接不会复制原文件数据,而是指向它。

cp命令用于复制文件或目录,它实际上在目标位置创建源文件数据的副本。使用cp后,原文件和副本是独立的;如果一个文件改变,另一个不会受影响。

extern “C” ?

在C++中,extern "C"是一种链接修饰符,用于告诉C++编译器按照C语言的方式来链接编译后的代码。这意味着,被extern "C"修饰的函数或变量在链接时使用C语言的名字修饰规则,而不是C++。这对于在C++代码中调用C语言写的库是非常重要,因为没有extern “C”,C++编译器可能无法正确链接C语言的函数或变量。

c++函数重载?

C++函数重载是指在相同作用域内,可以定义多个名称相同但是参数列表不同的函数。编译器根据函数被调用时提供的参数类型和个数来决定调用哪个版本的函数。这允许程序员使用相同的函数名执行不同的操作。

收集整理了一份2024年最新C++开发学习资料,既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C++开发知识点,真正体系化!
包含大厂面经、学习笔记、实战项目、大纲路线、讲解视频 领取地址:
https://docs.qq.com/doc/DR2N4d25LRG1leU9Q
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值