本次分享一位 25 届应届生的深信服技术岗一面面经,面试整体难度偏基础,核心考察计算机核心基础与算法能力,希望能为同届校招同学提供参考。
一、学生个人情况介绍
本次分享的面经来自25 届应届毕业生,应聘深信服校招技术岗,本次为一面环节。该同学反馈面试体验良好,无超纲冷门考点,考察重点集中在C++ 编程语言、计算机网络、操作系统、SQL 基础 及经典手撕算法题,是典型的技术岗基础能力验证型面试。
二、面试企业和部门介绍
1. 企业介绍
深信服科技股份有限公司是国内头部的网络安全、云计算与 IT 基础设施解决方案提供商,业务覆盖政企、金融、教育、医疗等多个领域。校招技术岗招聘中,深信服高度重视候选人的计算机基础功底(网络、操作系统)、编程语言实战能力(以 C/C++ 为主)和算法思维,核心考察 “基础是否扎实” 而非 “冷门知识储备”。
2. 面试部门
本次面试为深信服通用技术岗一面,未明确细分具体业务部门,所有问题均围绕通用技术能力展开,无针对性的业务场景问题,聚焦基础能力验证。
三、面试核心内容与回答思路
面试内容分为五大模块,以下为每个问题的提问方向、详细回答思路及核心要点:
模块一:C++(核心编程语言考察)
C++ 是本次面试的重点考察方向,问题均为技术岗高频基础考点,注重 “理解原理 + 能落地解释”。
问题 1:介绍 C++ 面向对象的三大特性
回答思路:先总述三大特性名称,再分别拆解每个特性的 “定义 + 核心价值 + 通俗示例”,让回答有层次、不空洞。
核心回答:
C++ 面向对象的三大核心特性是继承、封装、多态,三者共同支撑 “代码复用、抽象化、逻辑灵活” 的编程思想:
- 继承:让子类获取父类的属性和方法,无需重复编写原有代码,同时可扩展新功能(如 “动物” 父类定义通用行为,“猫 / 狗” 子类继承后扩展 “叫” 的具体逻辑);
- 封装:将事物的属性和方法抽象为类,通过
public/private/protected控制访问权限,对不可信的外部隐藏核心数据(如类的私有成员仅能被内部方法修改,避免外部误操作); - 多态:同一消息发送给不同对象,执行不同逻辑 —— 编译时多态通过函数重载实现,运行时多态通过虚函数 / 纯虚函数实现(如父类指针指向子类对象,调用同一方法时执行子类逻辑)。
问题 2:C++ 11 有哪些新特性?
回答思路:优先列举 “高频实用” 的新特性,每个特性说明 “解决的问题 + 简单使用示例”,避免仅罗列名词。
核心回答:
C++11 是 C++ 的里程碑版本,新增特性大幅提升开发效率,核心常用的有:
nullptr:替代原有NULL(NULL本质是 0,易引发指针 / 整数类型混淆),专门表示空指针,类型更安全;- 类型推导关键字:
auto让编译器自动推导变量类型(如auto i = 10;推导为int),decltype推导表达式类型,减少复杂类型的冗余书写; - 基于范围的 for 循环:简化容器遍历,如
for(auto& i : res){}可直接遍历数组 / 容器,无需手动控制下标; - Lambda 表达式:支持定义匿名函数,适用于临时简单逻辑(如容器排序时直接写排序规则);
- 右值引用与 move 语义:解决临时对象的拷贝效率问题,通过
std::move实现资源转移,减少内存拷贝; - 其他:类 / 结构体初始化列表(
struct A{int a;}; A a{10};)、std::forward_list(单向链表,节省内存)等。
问题 3:hashtable 中解决冲突有哪些方法?
回答思路:先说明哈希冲突的本质(不同 key 映射到同一地址),再分点介绍每种方法的 “核心逻辑 + 优缺点”,突出工业界常用方案。
核心回答:
哈希冲突是 “不同 key 经哈希函数计算后得到同一数组下标”,常见解决方法有 4 种:
- 线性探测:冲突时向后依次找空位(表尾则回到表头),实现简单但易出现 “连续聚集”,降低查找效率;
- 开链法(拉链法):每个哈希位置维护一个链表,冲突的 key 插入对应链表,无聚集问题,是工业界主流方案(如 C++
unordered_map底层实现); - 再散列:冲突时用另一哈希函数重新计算地址,直到找到空位,避免聚集但增加哈希计算开销;
- 二次探测:冲突时按平方步长(1²、2²、3²…)找空位,相比线性探测减少聚集,若步长为随机数则为伪随机探测。
问题 4:区分int *p[10]和int (*p)[10](指针数组 vs 数组指针)
回答思路:结合 “运算符优先级” 拆解语法,明确 “核心是数组” 还是 “核心是指针”,配合通俗解释。
核心回答:
区分的关键是
[]优先级高于*,核心看 “本质是数组还是指针”:int *p[10]:指针数组 —— 先构成数组p[10],数组的每个元素是int*类型(指向 int 的指针),核心是 “数组”;int (*p)[10]:数组指针 ——()提升*优先级,先构成指针p,该指针指向 “包含 10 个 int 元素的数组”,核心是 “指针”。
模块二:操作系统
操作系统考察聚焦 “内存管理” 和 “数据存储”,均为技术岗必考点,注重 “对比记忆 + 原理理解”。
问题 5:堆和栈的区别
回答思路:从 “管理方式、内存机制、空间大小、碎片、生长方向、分配方式、效率”7 个维度对比,结合通俗解释辅助理解。
核心回答(表格梳理):
| 对比维度 | 堆 | 栈 |
|---|---|---|
| 管理方式 | 程序员手动控制(new/delete),易内存泄漏 |
编译器自动管理,出作用域自动释放 |
| 内存管理机制 | 基于空闲链表分配,找首个足够大的内存块 | 连续内存,剩余空间足够则分配,否则栈溢出 |
| 空间大小 | 不连续,受虚拟内存限制(32 位系统理论 4G),空间大且灵活 | 连续,大小固定(Windows 默认 2M),空间小 |
| 碎片问题 | 频繁new/delete易产生内存碎片,降低效率 |
先进后出,进出一一对应,无碎片 |
| 生长方向 | 向上(高地址方向) | 向下(低地址方向) |
| 分配方式 | 仅动态分配 | 静态分配(局部变量)+ 动态分配(alloca函数),均自动释放 |
| 分配效率 | 函数库实现,机制复杂,效率低 | 系统底层支持(专用寄存器 / 指令),效率高 |
问题 6:大小端存储是什么意思?如何区分?
回答思路:先定义大小端,结合数值示例说明存储方式,再给出两种可运行的代码判断方法,解释核心原理。
核心回答:
1. 大小端定义
大小端是多字节数据的内存存储顺序,核心区别:
- 大端存储:高字节存低地址(符合人类阅读习惯,如 0x12345678,低地址存 0x12);
- 小端存储:低字节存低地址(主流操作系统采用,如 0x12345678,低地址存 0x78);
注:网络传输用大端,Socket 编程需将主机小端转为网络大端。
2. 代码判断方法
方法一:强制类型转换(利用 int 转 char 仅保留低地址字节)
cpp
运行
#include <iostream>
using namespace std;
int main() {
int a = 0x1234;
char c = (char)a; // 仅保留低地址字节
if (c == 0x12) cout << "大端" << endl;
else if (c == 0x34) cout << "小端" << endl;
return 0;
}
方法二:联合体(利用成员共享内存的特性)
cpp
运行
#include <iostream>
using namespace std;
union endian {
int a; // 4字节,与ch共享内存
char ch; // 仅占用a的低地址部分
};
int main() {
endian val;
val.a = 0x1234;
if (val.ch == 0x12) cout << "大端" << endl;
else if (val.ch == 0x34) cout << "小端" << endl;
return 0;
}
模块二:计算机网络
网络考察聚焦 “TCP 可靠性” 和 “会话管理”,均为校招高频考点,注重 “机制理解 + 对比分析”。
问题 7:TCP 是如何保证可靠传输的?
回答思路:从 “确认重传、数据校验、分片排序、流量控制、拥塞控制”5 个维度展开,每个机制说明 “作用 + 实现方式”,对比 UDP 突出 TCP 的可靠性。
核心回答:
TCP 通过 5 大核心机制保证可靠传输:
- 确认与重传:接收方收到报文返回 ACK 确认,发送方超时未收到则重传;
- 数据校验:TCP 报文头含校验和,接收方验证报文是否损坏,损坏则丢弃并触发重传;
- 分片与排序:按 MTU 合理分片,接收方缓存未按序分片,排序后交给应用层(UDP 分片丢失则丢弃整个数据报);
- 流量控制:基于滑动窗口,接收方通过窗口大小告知发送方接收能力,避免接收方处理不及时丢包;
- 拥塞控制:基于拥塞窗口,通过慢启动、拥塞避免等算法,减少网络拥塞时的发送速率。
问题 8:Cookies 和 Session 分别存放在哪里?
回答思路:先明确存储位置,再补充 “安全性 + 数据大小” 等延伸点,让回答更完整。
核心回答:
Cookie 和 Session 是维持会话的核心机制,核心区别在存储位置:
- Cookie:存储在客户端(浏览器),是服务器发送的小型文本文件,大小受限(约 4KB),安全性低(易被篡改),可设置过期时间;
- Session:存储在服务端(内存 / 数据库 / 缓存),服务器生成唯一 SessionID 并通过 Cookie 传递给客户端,数据更安全、无大小限制,适用于存储敏感信息(如登录状态)。
模块三:SQL
考察分组统计的基础语法,聚焦
GROUP BY的核心使用,注重 “需求拆解 + 语法正确性”。问题 9:班级成绩表(grades),区分 sex 为 male 和 female,如何写 SQL?
回答思路:先明确需求(按性别分组,统计人数 + 平均分),再给出 SQL 语句,解释核心关键字的作用。
核心回答:
需求是按性别(male/female)分组,统计每组的学生数量和平均成绩,SQL 语句及解释如下:
sql
SELECT
sex, -- 分组维度:性别
COUNT(*) AS total_students, -- 统计每组学生数
AVG(score) AS average_score -- 计算每组平均分
FROM grades
WHERE sex IN ('male', 'female') -- 筛选有效性别(可选)
GROUP BY sex; -- 按性别分组
模块四:手撕算法(现场编码)
算法题考察经典题型,注重 “代码逻辑正确 + 边界条件处理”,以下为完整可运行代码及思路:
算法题 1:手写快速排序
核心思路:分治思想 —— 选基准值→分区(小于基准放左,大于放右)→递归排序左右子数组,注意边界条件(
low >= high时终止递归)。cpp
运行
#include <iostream>
#include <vector>
using namespace std;
// 分区函数:返回基准值的正确下标
int partition(vector<int>& nums, int low, int high) {
int pivot = nums[high]; // 选最右元素为基准
int i = low - 1; // 小于基准的区域边界
for (int j = low; j < high; j++) {
if (nums[j] <= pivot) {
i++;
swap(nums[i], nums[j]);
}
}
swap(nums[i+1], nums[high]); // 基准值归位
return i + 1;
}
// 快速排序递归函数
void quickSort(vector<int>& nums, int low, int high) {
if (low < high) { // 边界条件:子数组长度>1才排序
int pi = partition(nums, low, high);
quickSort(nums, low, pi - 1); // 排序左子数组
quickSort(nums, pi + 1, high); // 排序右子数组
}
}
// 测试示例
int main() {
vector<int> nums = {3,1,4,1,5,9,2,6};
quickSort(nums, 0, nums.size()-1);
for (int num : nums) cout << num << " "; // 输出:1 1 2 3 4 5 6 9
return 0;
}
算法题 2:判断链表是否有环
核心思路:快慢指针法(龟兔赛跑)—— 快指针走 2 步,慢指针走 1 步,若相遇则有环;若快指针到链表尾则无环,注意空链表 / 单节点的边界条件。
cpp
运行
#include <iostream>
using namespace std;
// 链表节点定义
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
// 判断链表是否有环
bool hasCycle(ListNode *head) {
// 边界条件:空链表/单节点无环
if (head == NULL || head->next == NULL) return false;
ListNode* slow = head; // 慢指针:走1步
ListNode* fast = head->next; // 快指针:走2步
while (slow != fast) {
if (fast == NULL || fast->next == NULL) return false; // 快指针到尾,无环
slow = slow->next;
fast = fast->next->next;
}
return true; // 相遇,有环
}
// 测试示例
int main() {
// 构造有环链表:1->2->3->4->2
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = head->next; // 环指向2
cout << (hasCycle(head) ? "有环" : "无环") << endl; // 输出:有环
return 0;
}
四、总结
关键点回顾
- 面试难度:深信服技术岗一面以基础为主,无偏题怪题,核心考察 C++、操作系统、计算机网络三大核心学科,SQL 和算法为常规经典题;
- 备考重点:编程语言聚焦 C++ 面向对象、指针、C++11 特性,基础学科注重 “原理理解” 而非死记硬背,算法掌握快排、链表判环等经典题;
- 回答技巧:回答问题时先总述核心要点,再分点拆解,结合 “通俗示例 / 应用场景” 说明,避免仅罗列知识点。
