jinchanchanwaji 发表于 2025-3-10 13:20:41

【大厂C++面试必刷手册】Day8:内存管理×虚函数×进程调度...

内存分配情况,存放在哪里。
[*]堆:动态分配内存,用于存放动态创建的对象。
[*]栈:自动分配和释放,存放函数局部变量和函数参数。
[*]数据区:存放全局变量和静态变量。
[*]代码区:存放程序的执行代码。
函数参数传递的方式和特点。
[*]值传递:函数接收参数值的一个副本,原始数据不会被函数修改。
[*]引用传递:函数接收参数的内存地址(引用),可以直接修改原始数据。
static和const的区别。static关键字用来定义静态变量,其生命周期为程序执行期间,但它的作用域限定于定义它的文件或函数内。
const关键字定义常量,其值在定义后不能被修改,用来保证数据的不变性。它只影响它所修饰的变量的可变性,而不影响其生命周期。
static修饰局部变量、全局变量、函数和类各有什么特点。
[*]静态局部变量:存储在数据区,生命周期贯穿程序执行期,但只在定义它的函数内可见。
[*]静态全局变量:作用域限定于定义它的文件内,对其他文件不可见。
[*]静态函数:其链接属性为内部,只能在定义它的文件内使用。
[*]静态类成员:属于类本身,而不是类的任何特定对象,所有对象共享同一个静态成员。
new和malloc,free和delete区别。
[*]new 和 delete 是C++中用于动态内存分配和释放的操作符。new 在分配内存的同时调用构造函数初始化对象,delete 释放内存前调用对象的析构函数。
[*]malloc 和 free 是C语言中用于动态内存分配和释放的函数。malloc 只分配内存,不初始化,free 只释放内存,不调用析构函数。
指针和引用区别。
[*]指针是一个变量,其值为另一个变量的地址,通过地址,可以直接访问和修改对应内存中的值。
[*]引用是别名,它为对象提供了一个新的名字,对引用的操作等同于对对象本身的操作。
[*]指针可以为空,引用必须绑定到一个对象。
[*]指针的值(即所指对象的地址)可以改变,但引用一旦与某个对象绑定,就不能再改变引用到其他对象。
深拷贝和浅拷贝。浅拷贝指的是复制对象的引用,而不是对象本身,因此原始对象和副本对象共享同一块内存地址。深拷贝则是复制对象及其包含的所有对象,副本和原始对象在内存中完全独立。
进程间通信,管道的特点。
[*]半双工通信:数据只能单向流动,如果需要双向通信,需要创建两个管道。
[*]数据流动是顺序的和阻塞的:数据按照发送的顺序接收,如果管道空则读操作阻塞,如果管道满则写操作阻塞。
[*]管道是用于有亲缘关系的进程间通信,如父子进程通信。
define特点,怎么定义一个a+b的宏。特点是:

[*]预处理阶段进行文本替换,不涉及类型检查。
[*]可定义常量和宏,提高代码复用性。
[*]宏可以包含参数,但不进行正确性检查。
定义一个执行a+b的宏,如下所示:
#define ADD(a, b) ((a) + (b))这里的 (a) 和 (b) 被括起来是为了避免展开时出现的运算优先级问题。
sizeof和strlen区别。sizeof 是一个编译时运算符,用来得到某个类型或变量在内存中的大小,单位是字节。
strlen 是一个运行时函数,用来计算字符串的长度,直到遇到第一个空字符 '\0',不包括 '\0'。
sprintf、strcpy和memcpy区别。sprintf:格式化数据并将结果字符串输出到指定的字符数组。strcpy:将一个以空字符结尾的字符串复制到另一个地址空间,包括空字符。memcpy:在内存中复制指定数量的字节,从一个位置到另一个位置,不关注数据类型,可能不处理空字符。
虚函数特点。
[*]支持动态多态性:允许通过基类指针或引用调用派生类的函数。
[*]运行时绑定:函数调用在运行时解析,而非编译时。
[*]存在虚表(vtable):每个有虚函数的类都有一个虚表。
[*]可以被派生类重写:派生类可以提供自己的虚函数实现。
[*]必须至少有一个函数体,除非声明为纯虚函数。
父类子类构造析构函数调用顺序。构造函数调用顺序:首先调用父类构造函数,然后调用子类构造函数。
析构函数调用顺序:首先调用子类析构函数,然后调用父类析构函数。
构造析构能否抛出异常,能否是虚函数。构造函数和析构函数都可以抛出异常,但应谨慎处理,以避免可能导致的资源泄露或不一致状态。
构造函数不能是虚函数,因为虚函数表(vtable)在构造时尚未建立。析构函数可以是虚函数,通常在基类中将析构函数声明为虚析构函数,以确保通过基类指针删除派生类对象时,能正确调用派生类的析构函数。
内存对齐。C++内存对齐是为了提高内存访问效率,确保数据结构按照某个固定的长度(对齐界限)存储。编译器会自动添加填充字节(padding),使得结构体的每个成员相对于结构体开始位置的偏移量是成员大小或某个特定数值(通常是2的幂)的整数倍。
STL有哪些容器,各自特点。
[*]序列容器:

[*]vector:动态数组,支持快速随机访问。
[*]list:双向链表,支持快速插入和删除。
[*]deque:双端队列,两端都可以快速插入和删除。
[*]关联容器:

[*]set:集合,元素唯一且自动排序。
[*]map:键值对集合,键唯一且自动排序。
[*]multiset:集合,元素可以重复,自动排序。
[*]multimap:键值对集合,键可以重复,自动排序。
[*]无序关联容器(C++11新增):

[*]unordered_set:集合,元素唯一,基于哈希表实现,不排序。
[*]unordered_map:键值对集合,键唯一,基于哈希表实现,不排序。
[*]unordered_multiset:集合,元素可以重复,基于哈希表实现,不排序。
[*]unordered_multimap:键值对集合,键可以重复,基于哈希表实现,不排序。
[*]适配器容器:

[*]stack:栈,后进先出。
[*]queue:队列,先进先出。
[*]priority_queue:优先队列,元素按优先级出队。
vector扩容如何实现。vector扩容通常通过创建一个更大的新内存空间,然后将原有元素复制或移动到新空间,之后释放原始内存空间来实现。扩容的大小通常是当前容量的两倍,以减少频繁扩容的开销。
map、set特点,怎么实现的。map 和 set 的特点是它们存储的元素是自动排序的,map 存储键值对,其中键是唯一的,而 set 只存储键且每个键是唯一的。
它们是通过平衡二叉搜索树(通常是红黑树)实现的,这个数据结构可以提供对元素的有序存储,以及在对数时间复杂度内进行元素查找、插入和删除操作。
内联函数。C++内联函数是一种通常用于优化小型、频繁调用的函数的编程技术。通过在函数声明前加inline关键字,编译器在调用处直接展开函数代码,以减少函数调用的开销。但最终是否内联取决于编译器的决定。
gdb如何debug,怎么传参。在GDB中进行调试,首先要启动GDB并加载你要调试的程序,可以用 gdb <your_program> 命令。传递参数可以在GDB中使用 set args <arg1> <arg2> ... 命令来设置命令行参数。然后,你可以使用像 run 来运行程序、break 设置断点、next 单步执行等命令来控制程序的执行并进行调试。
指针的初始化和释放。指针的初始化应该将其设为nullptr(C++11及以后)或NULL,以指示它尚未指向任何对象。当指针分配了动态内存后(例如,使用new),完成使用后应使用delete(对于单个对象)或delete[](对于对象数组)来释放分配的内存,然后把指针重新设置为nullptr,避免悬挂指针的问题。
三个进程都需要读写一块内存,如何调度。为了协调三个进程对同一块内存区域的读写访问,可以使用互斥锁(mutexes)或读写锁(read-write locks)。互斥锁确保任一时间只有一个进程可以访问该内存。读写锁允许多个读取者同时访问,但写入者独占访问。适当的锁机制需要根据访问模式和性能要求选择。

页: [1]
查看完整版本: 【大厂C++面试必刷手册】Day8:内存管理×虚函数×进程调度...