后端开发面经系列 -- 滴滴C++一面面经

滴滴C++一面面经

公众号:阿Q技术站

来源:https://www.nowcoder.com/feed/main/detail/38cf9704ef084e27903d2204352835ef

1、const在C和C++区别,const定义的类成员变量如何初始化?

区别
  1. C中的const:
    • 在C中,const 用于声明只读变量,即变量的值不能被修改。
    • C中的常量通常使用 #define 预处理指令定义,但是使用 const 关键字也是一种常见的方式。

示例:

const int MAX_VALUE = 100;
int main() {const int a = 10;// 在C中,试图修改 const 变量的值会导致编译错误// a = 20; // 错误return 0;
}
  1. C++中的const:
  • 在C++中,const 用于指定不可变数据,包括不可变对象、不可变函数参数以及不可变成员函数。
  • 在C++中,还可以使用 const 对象来调用 const 成员函数,但是不能调用非 const 成员函数。

示例:

class MyClass {
public:void func() const {// const 成员函数可以访问但不能修改非 const 成员变量// value = 100; // 错误}
private:int value;
};int main() {const int b = 20; // 常量MyClass obj;obj.func(); // 调用 const 成员函数return 0;
}
如何初始化?

在C和C++中,const定义的类成员变量在初始化时可以通过初始化列表或构造函数的形式进行初始化。

在C++中,可以在类的构造函数初始化列表中对const成员变量进行初始化,因为const成员变量在创建对象时必须进行初始化。示例如下:

#include <iostream>class MyClass {
public:MyClass(int value) : constMember(value) {// 可以在构造函数的初始化列表中初始化const成员变量}void printConstMember() {std::cout << "constMember: " << constMember << std::endl;}private:const int constMember;
};int main() {MyClass obj(10);obj.printConstMember();return 0;
}

在C语言中没有类的概念,但可以使用结构体来模拟类的功能。对于const成员变量的初始化,可以在结构体的初始化函数中进行初始化。示例如下:

#include <stdio.h>struct MyClass {const int constMember;
};void MyClass_init(struct MyClass *obj, int value) {obj->constMember = value;
}void MyClass_print(const struct MyClass *obj) {printf("constMember: %d\n", obj->constMember);
}int main() {struct MyClass obj;MyClass_init(&obj, 10);MyClass_print(&obj);return 0;
}

在C++中,推荐使用构造函数的初始化列表来初始化const成员变量;在C语言中,使用初始化函数来初始化const成员变量。

2、空的class占用多少内存?

空的类(或结构体)在C++中占用的内存空间取决于编译器的实现。一般情况下,空的类或结构体会占用一个字节的内存空间。这是因为C++标准规定,每个对象(包括空对象)在内存中都应该有独一无二的地址,以便于区分不同的对象。

3、sizeof一个类,类有5个函数,其中2个虚函数,还有一个整型,一个short。sizeof结果?

class MyClass {
public:virtual void func1();virtual void func2();void func3();void func4();void func5();private:int x;short y;
};

根据C++的对齐规则,非静态数据成员的对齐值通常为其自身大小或所在平台的最大对齐值中较小的一个。对于大多数平台,int 的对齐值为4字节,short 的对齐值为2字节。

MyClass 的大小计算如下:

  • 非静态数据成员 int x; 占用4字节。
  • 非静态数据成员 short y; 占用2字节。
  • 虚函数表指针(vptr):对于包含虚函数的类,每个对象都会有一个指向虚函数表的指针,通常占用4字节或8字节(取决于平台)。
  • 虚函数 void func1();void func2(); 的存在会在虚函数表中占用额外空间,但不会直接影响类的大小。
  • 其他非静态函数不会影响类的大小。

在32位平台上,MyClass 类的大小为 4(int x) + 2(short y) + 4(虚函数表指针) = 10 字节。

4、map、set底层,讲讲红黑树,为什么不用哈希表。go字典的底层?

在C++中,std::mapstd::set 通常使用红黑树作为底层数据结构,而不是哈希表。这是因为红黑树有着良好的平衡性能,在有序性和插入/删除操作的效率之间取得了一个很好的平衡。

红黑树是一种自平衡的二叉查找树,具有以下特性:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色的。
  3. 每个叶子节点(NIL节点,空节点)是黑色的。
  4. 如果一个节点是红色的,则它的子节点必须是黑色的(反之不一定成立)。
  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树的平衡性质保证了在最坏情况下,查找、插入和删除操作的时间复杂度为 O(log n),其中 n 是树中元素的数量。相比之下,哈希表在理想情况下具有 O(1) 的插入、删除和查找时间复杂度,但在最坏情况下可能达到 O(n)。此外,红黑树提供了有序性,可以方便地进行区间查找和遍历操作。

Go语言中的字典(map)使用了一种称为哈希表的数据结构作为底层实现。哈希表通过将键映射到存储桶(bucket)中的位置来实现快速的查找、插入和删除操作。在Go语言中,哈希表使用了开放定址法和链表结构来解决哈希冲突,当链表长度超过一定阈值时,会将链表转换为红黑树,以提高性能。

5、红黑树如何把key从整型换成类,需要overwrite哪些?

  1. 比较函数的重写: 红黑树需要比较键的大小来进行插入、查找等操作。当键由整型换成类时,需要重写类的比较函数,使其能够比较两个键的大小。通常需要实现 <>== 等比较操作符,或者提供自定义的比较函数。
  2. 哈希函数的重写: 如果使用哈希表来实现红黑树,需要重写类的哈希函数,将键转换为哈希值。哈希函数的设计需要考虑到哈希值的均匀分布,以提高哈希表的性能。
  3. 节点结构的修改: 红黑树的节点结构通常包括键、值、颜色和指向子节点的指针等信息。当键由整型换成类时,节点结构需要修改,将整型键替换为类对象。同时,需要保留节点的值、颜色和指针等信息。
  4. 插入、删除和查找操作的修改: 需要根据新的键类型重写插入、删除和查找操作。这些操作需要根据键的大小来决定节点的插入位置、删除方式和查找路径。
  5. 平衡性维护的修改: 红黑树需要保持平衡性质,插入和删除操作可能会破坏平衡,需要进行旋转等操作来恢复平衡。当键由整型换成类时,需要根据新的键类型进行平衡性维护的修改。

6、bss和data区别,static放在哪,static未初始化放在哪?

  1. bss段: bss段用于存储未初始化的全局变量和静态变量。在程序加载时,操作系统会将bss段中的变量初始化为0或空值(对于不同编译器和系统可能有所不同)。bss段不占用可执行文件的存储空间,而是在程序加载时由操作系统分配。因此,bss段中的变量在可执行文件中并不占用实际空间,只是在程序运行时分配空间。
  2. data段: data段用于存储已经初始化的全局变量和静态变量。在程序加载时,操作系统会将data段中的变量初始化为指定的值。与bss段不同,data段中的变量在可执行文件中占用实际空间,因为它们的初始值已经在编译时确定。
  3. static关键字: 在C/C++中,static关键字用于声明静态变量和函数。静态变量可以放在bss段或data段中,取决于是否进行了初始化。如果静态变量进行了初始化,则存储在data段;如果未进行初始化,则存储在bss段。
  4. 未初始化的静态变量: 未初始化的静态变量(即在声明时未指定初始值的静态变量)存储在bss段中。当程序加载时,操作系统会将bss段中的未初始化静态变量初始化为0或空值。

7、进程和线程,nginx怎么做多进程,进程通信方式,mmap可以做共享内存吗?

  1. 进程(Process): 进程是程序的一次执行过程,是操作系统进行资源分配和调度的基本单位。每个进程拥有独立的内存空间、数据栈以及其他资源,进程间相互独立,需要通过进程间通信(IPC,Inter-Process Communication)来进行数据交换和同步。Nginx采用多进程模型来处理客户端请求,每个进程负责处理一部分请求。
  2. 线程(Thread): 线程是进程的一个执行流,是操作系统能够进行运算调度的最小单位。线程共享所属进程的内存空间和资源,不同线程间可以直接访问共享数据,但也需要考虑线程同步和互斥的问题。线程通常比进程轻量,创建和切换的开销较小。
  3. 进程间通信方式: 进程间通信有多种方式,包括管道、信号、消息队列、共享内存和套接字等。在Nginx中,多个进程通过共享一个文件描述符来实现进程间通信,可以通过文件锁(flock)等机制来实现进程间的同步和互斥。
  4. mmap和共享内存: mmap是一种将文件或设备映射到内存的方法,可以实现文件和内存之间的直接映射。共享内存是一种特殊的内存映射,允许多个进程共享同一块物理内存,从而实现进程间的数据共享。在Linux系统中,可以使用mmap系统调用来创建共享内存区域,多个进程可以将同一文件映射到各自的地址空间,实现数据的共享和通信。在Nginx中,也可以使用共享内存来实现进程间的通信和数据共享。

8、关系型数据库特点,redis过期管理,定时器原理?

关系型数据库的特点:

  1. 数据以表格的形式存储,表格由行和列组成,每行代表一个记录,每列代表一个属性。
  2. 支持 SQL(Structured Query Language)作为查询语言,可以方便地进行数据查询和操作。
  3. 支持事务(Transaction)的概念,保证数据的一致性和完整性。
  4. 支持 ACID(原子性、一致性、隔离性、持久性)特性,保证数据的可靠性和安全性。
  5. 支持复杂的数据模型和关联查询,适用于处理复杂的数据结构和关系。

Redis过期管理: Redis中可以通过设置过期时间(expire)来管理键值对的过期时间,当键值对的过期时间到达时,Redis会自动删除该键值对。过期时间可以通过EXPIRE命令设置,也可以在设置键值对时直接指定过期时间。Redis使用定期删除(定时器)和惰性删除两种方式来管理过期键值对。定期删除是指Redis每隔一段时间会随机检查一部分键值对的过期时间,删除已过期的键值对。惰性删除是指在获取键值对时,Redis会先检查该键值对是否过期,如果过期则删除。

定时器原理: 定时器通常由操作系统提供,用于在指定的时间间隔内执行某个操作或触发某个事件。在Linux系统中,定时器通常是通过系统调用timer_create创建一个定时器对象,然后通过timer_settime设置定时器的触发时间和间隔。定时器可以是相对时间(相对于当前时间的时间间隔)或绝对时间(具体的时间点)。定时器的触发通常是通过信号(如SIGALRM)来实现的,当定时器到达指定的时间时,操作系统会发送信号给应用程序,应用程序可以通过信号处理函数来处理定时器触发事件。

9、tcp和udp区别,tcp如何解析json,udp会考虑这个问题吗?

区别
  1. 连接性:TCP是面向连接的协议,建立连接后进行数据传输,保证数据的可靠性和顺序性;而UDP是无连接的协议,发送数据时不需要建立连接,也不保证数据的可靠性和顺序性。
  2. 数据传输方式:TCP使用流式传输,数据被分割成TCP报文段进行传输,保证数据的完整性;UDP使用数据报传输,每个UDP数据包(数据报)独立传输,不保证数据的完整性。
  3. 重传机制:TCP具有重传机制,当数据丢失或损坏时会进行重传,保证数据的可靠性;UDP不具有重传机制,一旦数据丢失或损坏就会丢失。
  4. 面向应用:TCP适用于对数据可靠性要求较高的应用,如文件传输、网页访问等;UDP适用于对实时性要求较高的应用,如音视频传输、在线游戏等。

解析JSON数据通常是在应用层完成的,与传输层协议无关。在TCP中,接收到的数据可以按照JSON格式解析;在UDP中,同样可以接收到JSON格式的数据,但由于UDP不保证数据的完整性,可能需要应用层自行处理丢失或损坏的数据。

10、反转链表

思路

这里给大家讲最经典的双指针法。

  1. 如果链表为空或者只有一个节点,直接返回头结点head。
  2. 初始化 pre 为 nullptr,cur 为头结点 head,node 为 cur 的下一个节点。
  3. 在循环中,不断更新 pre、cur 和 node 的值,使得 cur 的 next 指向 pre,然后将 pre、cur 和 node 分别向后移动一位。
  4. 当 cur 移动到链表末尾时,pre 就是反转后的新头结点。

演示过程:

初始状态:

第一步:

先定义一个空节点并初始化为nullptr,分别将这两个指针指向这个空节点和头结点,再定义一个节点用来临时存放节点。

ListNode* pre = nullptr; // 初始化 pre 为 nullptr

ListNode* cur = head; // 初始化 cur 为头结点

ListNode* node = nullptr; // 初始化 node 为 nullptr

第二步:

node = cur->next; // 保存当前节点的下一个节点

cur->next = pre; // 当前节点的 next 指向 pre,完成反转

第三步:

pre = cur; // 更新 pre
cur = node; // 更新 cur

到这里,其实我们就可以使用一个循环,让继续这两步操作。不过为了大家更加看明白,我就将这个示例画完吧。

第四步:

node = cur->next; // 保存当前节点的下一个节点

cur->next = pre; // 当前节点的 next 指向 pre,完成反转

第五步:

pre = cur; // 更新 pre
cur = node; // 更新 cur

第六步:

node = cur->next; // 保存当前节点的下一个节点

cur->next = pre; // 当前节点的 next 指向 pre,完成反转

第七步:

pre = cur; // 更新 pre
cur = node; // 更新 cur

第八步:

node = cur->next; // 保存当前节点的下一个节点

cur->next = pre; // 当前节点的 next 指向 pre,完成反转

第九步:

pre = cur; // 更新 pre
cur = node; // 更新 cur

第十步:

node = cur->next; // 保存当前节点的下一个节点

cur->next = pre; // 当前节点的 next 指向 pre,完成反转

第十一步:

pre = cur; // 更新 pre
cur = node; // 更新 cur

此时cur==nullptr,退出循环。

参考代码
C++
#include <iostream>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};class Solution {
public:ListNode* reverseList(ListNode* head) {if (head == nullptr || head->next == nullptr) {return head; // 如果链表为空或者只有一个节点,直接返回头结点}ListNode* pre = nullptr; // 初始化 pre 为 nullptrListNode* cur = head; // 初始化 cur 为头结点ListNode* node = nullptr; // 初始化 node 为 nullptrwhile (cur != nullptr) {node = cur->next; // 保存当前节点的下一个节点cur->next = pre; // 当前节点的 next 指向 pre,完成反转pre = cur; // 更新 precur = node; // 更新 cur}return pre; // pre 就是反转后的新头结点}
};int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);Solution solution;ListNode* newHead = solution.reverseList(head);while (newHead != nullptr) {std::cout << newHead->val << " ";newHead = newHead->next;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3017948.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis分布式缓存】分片集群

Redis 分片集群 搭建分片集群 集群结构 分片集群需要的节点数量较多&#xff0c;这里我们搭建一个最小的分片集群&#xff0c;包含3个master节点&#xff0c;每个master包含一个slave节点&#xff0c;结构如下&#xff1a; 这里我们会在同一台虚拟机中开启6个redis实例&…

计算机毕业设计Python+Vue.js天气预测系统 中国气象质量采集与可视化 天气数据分析 天气可视化 天气大数据 天气爬虫 大数据毕业设计

摘要 随着科技技术的不断发展&#xff0c;人民物质生活质量不断提高&#xff0c;我们越来越关注身边的气象、空气等地理环境。对于普通居民我们会选择合适的气象进行出游&#xff0c;提高精神层面的生活质量&#xff1b;对于企业会关注气象变换状况&#xff0c;来定制相关的生产…

91、动态规划-不同的路径

思路&#xff1a; 首先我们可以使用暴力递归解法&#xff0c;无非就是每次向下或者向右看看是否有解法&#xff0c;代码如下&#xff1a; public class Solution {public int uniquePaths(int m, int n) {return findPaths(0, 0, m, n);}private int findPaths(int i, int j,…

解决Python中的 `ModuleNotFoundError: No module named ‘fcmeans‘` 错误

ModuleNotFoundError: No module named fcmeans 解决Python中的 ModuleNotFoundError: No module named fcmeans 错误如何解决这个错误fcmeans 库简介应用实例 解决Python中的 ModuleNotFoundError: No module named fcmeans 错误 在进行数据科学或机器学习项目时&#xff0c;…

【CTF Web】XCTF GFSJ0477 backup Writeup(备份文件+源码泄漏+目录扫描)

backup X老师忘记删除备份文件&#xff0c;他派小宁同学去把备份文件找出来,一起来帮小宁同学吧&#xff01; 解法 使用 dirsearch 扫描目录。 dirsearch -u http://61.147.171.105:49361/下载&#xff1a; http://61.147.171.105:64289/index.php.bak打开 index.php.bak&am…

【机器学习系统的构建】从模型开发的过程讲清楚K-Fold 交叉验证 (Cross-Validation)的原理和应用

0、前言 最近在学习集成学习的时候了解到了k折交叉验证&#xff0c;其实在之前学习吴恩达老师的课程中也学过交叉验证&#xff0c;但是当时也不是很明白。这次借着自己的疑问以及网上搜找资料&#xff0c;终于把交叉验证给弄明白了。 在弄清楚前&#xff0c;我有这样几个疑问…

交友软件源码-源码+搭建+售后,上线即可运营聊天交友源码 专业语聊交友app开发+源码搭建-快速上线

交友小程序源码是一种可以帮助开发者快速搭建交友类小程序的代码模板。它通常包括用户注册、登录、个人信息编辑、匹配推荐、好友聊天等常见功能&#xff0c;以及与后台数据交互的接口。使用这种源码可以极大地缩短开发时间&#xff0c;同时也可以根据自己的需求进行二次开发和…

Amazon Bedrock 托管 Llama 3 8B70B

Amazon Bedrock 托管 Llama 3 8B&70B&#xff0c;先来体验&#xff1a;&#xff08;*实验环境账号有效期为1天&#xff0c;到期自动关停&#xff0c;请注意重要数据保护&#xff09; https://dev.amazoncloud.cn/experience/cloudlab?id65fd86c7ca2a0d291be26068&visi…

串的模式匹配之KMP算法实现

概述 函数刻画 主串位置不变&#xff0c;next值就是模式串(子串)比较后应跳转的位置 不同位置 next[j]函数 next由模式串决定&#xff0c;看模式串当前比较位的前串中前后缀相同的个数来得k-1的值&#xff0c;next[当前位]k1 小补充 PM值&#xff1a;也称部分匹配值&#xf…

【知识碎片】2024_05_07

今天记录了两个代码和C的几个破碎知识。 第一段代码是基础型的&#xff0c;关于数组。第二段代码是二分的&#xff0c;一开始没通过全部案例&#xff0c;值得再看。 每日代码 1.记负均正 输入一个数组&#xff0c;输出负数的个数&#xff0c;整数的平均值&#xff08;0都不参…

C++:week2:C语言中高级

文章目录 (八) 指针0.概念1.指针基础(1)指针的声明(2)指针的两个基本操作①取地址运算符 &②解引用运算符 * (3)野指针①野指针②空指针③指针变量的赋值 vs 指针变量指向对象的赋值 (4)指针的应用①指针作为参数进行传递②指针作为返回值③拓展&#xff1a;栈帧 (5)常量指…

怎么将pdf的文件内容保存到mysql数据库中?

要将PDF导入到MYSQL&#xff0c;首先一步就是要先将PDF内容结构化&#xff0c;如果其内容为非结构化&#xff0c;则导入MYSQL的意义不大&#xff0c;具体操作方法如下&#xff1a; 将PDF文件的内容保存到MySQL数据库中通常涉及几个步骤。PDF文件包含的是格式化文本、图像和其他…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐PyMuPDF+tqdm)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 文章目录 PyMuPDF 使用体验与评估1 安装指南2 测试代码3 测试结果3.1 转 HTML …

20240507 ubuntu20.04+ros noetic 跑通lioslam

任务&#xff1a;跑通lioslam 主要参考博客 IMU激光雷达融合使用LIO-SAM建图学习笔记——详细、长文、多图、全流程_ubuntu_AIDE回归线-GitCode 开源社区 (csdn.net) 1.不要用这一句 wget -O ~/Downloads/gtsam.zip https://github.com/borglab/gtsam/archive/4.0.0-alpha2…

华为eNSP中型企业局域网网络规划设计(下)

→b站传送门&#xff0c;感谢大佬← →华为eNSP中型企业局域网网络规划设计&#xff08;上&#xff09;← →拓扑图传送门&#xff0c;可以自己配置着玩← 配置ospf AR3 [AR3]ospf 1 router-id 3.3.3.3 //出口默认路由 [AR3-ospf-1]default-route-advertise always #area…

DeepSeek发布全新开源大模型,GPT-4级别能力 价格仅百分之一

最新国产开源MoE大模型&#xff0c;刚刚亮相就火了。 DeepSeek-V2性能达GPT-4级别&#xff0c;但开源、可免费商用、API价格仅为GPT-4-Turbo的百分之一。 因此一经发布&#xff0c;立马引发不小讨论。 从公布的性能指标来看&#xff0c;DeepSeek-V2的中文综合能力超越一众开源…

Redis是什么? 日常运维 Redis 需要注意什么 ? 怎么降低Redis 内存使用 节省内存?

你的项目或许已经使用 Redis 很长时间了&#xff0c;但在使用过程中&#xff0c;你可能还会或多或少地遇到以下问题&#xff1a; 我的 Redis 内存为什么增长这么快&#xff1f;为什么我的 Redis 操作延迟变大了&#xff1f;如何降低 Redis 故障发生的频率&#xff1f;日常运维…

25_Scala集合Tuple

文章目录 tuple1.元组定义2.Tuple元素访问3.如果元素的len2&#xff0c;称之为键值对对象&#xff0c;也称之为对偶元组4.补充上节Map5.Map集合遍历6.集合之间相互转化 tuple 概念&#xff1a;scala语言采用特殊的方式将无关的数据作为一个整体&#xff0c;组合在一起’ 1.元…

【数据结构】顺序表专题详解(带图解析)

最好的时光&#xff0c;在路上;最好的生活&#xff0c;在别处。独自上路去看看这个世界&#xff0c;你终将与最好的自己相遇。&#x1f493;&#x1f493;&#x1f493; 目录 •&#x1f319;说在前面 &#x1f34b;知识点一&#xff1a;什么是数据结构 • &#x1f330;1.什…

一览函数式编程

文章目录 一、 什么是函数式编程1.1 编程范式1.1.1 命令式编程(Imperative Programming)范式1.1.2 声明式编程(Declarative Programming)范式1.1.3 函数式编程(Functional Programming)范式1.1.4 面向对象编程(Object-Oriented Programming)范式1.1.5 元编程(Metaprogramming)范…