自学内容网 自学内容网

C++面试速通宝典——15

254. STL有哪些容器?各自特点?

  1. 序列容器:
    1. vector:动态数组,支持快速随机访问。
    2. list:双向链表,支持快速插入和删除。
    3. deque:双端队列,两端都可以快速插入和删除。
  2. 关联容器:
    1. set:集合,元素唯一且自动排序。
    2. map:键值对集合,键唯一且自动排序。
    3. multiset:集合,元素可以重复,自动排序。
    4. multimap:键值对集合,键可以重复,自动排序。
  3. 无序关联容器:
    1. unordered_set:集合,元素唯一,基于哈希表实现,不排序。
    2. unordered_map:键值对集合,键唯一,基于哈希表实现,不排序。
    3. unordered_multiset:集合,元素可以重复,基于哈希表实现,不排序。
    4. unordered_multimap:键值对集合,键可以重复,基于哈希表实现,不排序。
  4. 适配器容器:
    1. stack:栈,后进先出。
    2. queue:队列,先进先出。
    3. priority_queue:优先队列,元素按优先级出队。

255. vector扩容如何实现?

‌‌‌‌  vector扩容通常通过创建一个更大的新内存空间,然后将原有元素复制或移动到新空间中,之后释放原始内存空间来实现。
‌‌‌‌  扩容的大小通常是当前容量的两倍,以减少频繁扩容的开销。

256. map、set特点,怎么实现的?

‌‌‌‌  map和set的特点是他们存储的元素是自动排序的,map存储键值对,其中键是唯一的,而set只存储键且每个键是唯一的。

‌‌‌‌  他们通过平衡二叉搜索树(通常是红黑树)实现的,这个数据结构可以提供对元素的有序存储,以及在对数时间复杂度内进行元素查找、插入和删除操作。

257. 内联函数

‌‌‌‌  C++内联函数是一种通常用于优化小型、频繁调用的函数的编程技术。通过在函数声明前加inline关键字,编译器在调用处直接展开函数代码,以减少函数调用的开销。但最终是否内联取决于编译器的决定。

258. GDB如何debug,怎么传参?

‌‌‌‌  在GDB中进行调试,首先要启动GDB并加载你要调试的程序,可以使用gdb<your_program>命令。传递参数可以在GDB中使用 set args < arg1>< arg2>… 命令来设置命令行参数。然后,你可以使用像run来运行程序、break设置断点、next单步执行等命令来控制程序的执行并进行调试。

解释
‌‌‌‌  GDB(GNU Debugger)是GNU项目下的一个强大的调试工具,用于调试C、C++、Fortran等多种编程语言的程序。它可以帮助开发者追踪程序的执行流程,查找和修复错误。GDB 提供了多种功能,如设置断点、单步执行、查看变量和内存等。

如何使用 GDB 进行调试?

‌‌‌‌  以下是使用 GDB 进行调试的基本步骤:

1. 编译你的程序

‌‌‌‌  在使用 GDB 调试之前,你需要确保你的程序是用调试信息编译的。通常,你可以通过在编译时加上 -g 选项来包含调试信息。例如,对于一个C++程序 main.cpp

g++ -g -o myprogram main.cpp
2. 启动 GDB

‌‌‌‌  启动 GDB 并加载你的程序:

gdb myprogram
3. 设置断点

‌‌‌‌  断点允许你在程序执行到某一行时暂停。例如,要在 main 函数的第一行设置一个断点,可以在 GDB 提示符下输入:

(gdb) break main

‌‌‌‌  你也可以在特定的行号或函数名处设置断点,例如:

(gdb) break 10  # 在第10行设置断点
(gdb) break MyClass::myFunction  # 在类 MyClass 的 myFunction 方法处设置断点

4. 运行程序

‌‌‌‌  在设置断点后,你可以通过以下命令运行程序:

(gdb) run

‌‌‌‌  如果你的程序需要命令行参数,可以在 run 命令后指定:

(gdb) run arg1 arg2 arg3
5. 单步执行

‌‌‌‌  当程序在断点处暂停时,你可以单步执行代码:

  • step(或 s):进入函数调用
  • next(或 n):执行下一行代码,但不进入函数
  • continue(或 c):继续运行程序,直到下一个断点
6. 查看变量和内存

‌‌‌‌  你可以查看变量的值:

(gdb) print variable_name

‌‌‌‌  你也可以查看内存地址:

(gdb) x /nfu address

这里的 n 是单元数,f 是显示格式,u 是单元大小。例如:

(gdb) x /4xb 0xaddress  # 查看地址 0xaddress 处的 4 个字节,以十六进制显示

一个完整的 GDB 调试示例

假设你有一个简单的C++程序 main.cpp

#include <iostream>
using namespace std;

void function(int a) {
    int b = a * 2;
    cout << "Value of b: " << b << endl;
}

int main(int argc, char* argv[]) {
    int x = 5;
    function(x);
    return 0;
}

编译程序

g++ -g -o myprogram main.cpp

启动 GDB

gdb myprogram

设置断点

(gdb) break main

运行程序

(gdb) run

程序在 main 处暂停后,单步执行

(gdb) next  # 执行下一行
(gdb) step  # 进入 function 函数

查看变量

(gdb) print x
(gdb) print b

继续运行程序

(gdb) continue

‌‌‌‌  通过这些步骤,你可以使用 GDB 来有效地调试你的程序,查找并修复错误。

259. 指针的初始化和释放

‌‌‌‌  指针的初始化应该将其设为nullptr(C++11及以后)或NULL,以指示它尚未指向任何对象。当指针分配了动态内存后(例如,使用new),完成使用后应使用delete(对于单个对象)或delete[](对于对象数组)来释放分配的内存,然后把指针重新设置为nullptr避免悬挂指针的问题。

260. 三个进程都需要读写一块内存,如何调度?

‌‌‌‌  为了协调三个进程对同一块内存区域的读写访问,可以使用互斥锁(mutexes)或读写锁(read-write locks)。

  1. 互斥锁确保任一时间只有一个进程可以访问该内存。
  2. 读写锁允许多个读取者同时访问,但写入者单独访问。
    ‌‌‌‌  
    ‌‌‌‌  适当的锁机制需要根据访问模式和性能要求进行选择。

261. vfork了解么?

‌‌‌‌  vfork是一个UNIX系统调用,用于创建一个新的进程,成为子进程,它与创建它的父进程共享相同的内存空间。vfork被设计用来在执行exec系列函数前作为一个临时步骤。它区别于fork,因为他不会复制父进程的地址空间,而是直接使用父进程的地址空间,直到子进程调用exec或exit。这样做的目的是为了提高性能,但缺点是可能导致父子进程之间的同步问题。现代系统上,vfork的行为通常与fork相似,或被clone系统调用所取代。

262. C++程序编译链接过程

  1. 预处理(Preprocessing):预处理器处理源代码文件中的预处理指令,如宏定义、条件编译指令和文件包含指令等,生成预处理后的代码。
  2. 编译(Compilation):编译期间预处理后的代码转换为汇编指令,并进行语法和语义分析,生成相应平台的汇编代码文件。
  3. 汇编(Assembly):汇编器将汇编代码转换为机器代码生成目标文件(通常是.obj或.o文件)。
  4. 链接(Linking):链接器将所有目标文件以及所需的库文件合并解决代码中的外部引用,并生成最终的可执行程序

263. 静态链接和动态链接的区别

静态链接

  1. 所有必要的库代码整合到最终的可执行文件中
  2. 创建大的可执行文件,因为所有的代码都包含其中。
  3. 在程序启动时不需要加载外部库,因为所有的功能都已经内嵌。
  4. 可执行文件不依赖外部的库文件,更易分发。

动态链接

  1. 可执行文件包含指向动态链接库(DLLs或.so文件)的引用,而不是可执行代码。
  2. 生成更小的可执行文件,因为只需要存储库引用。
  3. 在程序运行时,需要额外的步骤来加载所需的动态库。
  4. 可执行文件依赖于外部库文件,因此需要确保相应的库在系统上可用。

264. 拷贝构造函数和移动构造函数的区别

拷贝构造函数

  1. 创建一个类的新对象时,他会从另一个同类型对象(源对象)复制数据。
  2. 它通常执行深拷贝,即分配新的资源,并复制对象的内容。

移动构造函数

  1. 也是创建新对象,但他从临时对象(rvalue,通常是将要销毁的对象)“移动资源”。
  2. 他执行浅拷贝,直接接管源对象的资源指针,并将源对象留在可销毁、但有效状态,这样就避免了资源的额外复制,提高了效率。

265. 浅拷贝和move有区别么?

有。

浅拷贝
‌‌‌‌  复制对象的指针或引用,新旧对象共享相同的底层数据资源

移动操作(move)

  1. 将资源从一个对象转移到另一个对象,原对象资源被置为null或有效但未定义状态,不再拥有资源。
  2. 只有移动构造函数或移动赋值操作符才参与移动操作。

266. 空类的大小

‌‌‌‌  空类的大小为1字节。

267. 类的继承方式有哪几种?区别是啥?

C++中类的继承方式有三种:

  1. 公有继承(public):基类的公有成员和保护成员继承后在派生类中保持原有状态,基类的私有成员不能直接访问。
  2. 保护继承(protected):基类的公有成员和保护成员继承后在派生类中变为保护成员。
  3. 私有继承(private):基类的公有成员和保护成员继承后在派生类中变为私有成员。

原文地址:https://blog.csdn.net/qq_43504141/article/details/142723918

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!