Mobile wallpaper 1
6412 字
32 分钟
冰岩2025秋招后端笔试题
2025-09-19
统计加载中...

Hi!

欢迎报名后端组的2025秋招!

本次笔试题作答时间为:9/19 22:00 - 9/22 23:59,时间很充足,自己安排即可。但请务必在作答截止前将你的答案及相关文件上传到这份问卷中并完成提交。可多次提交,以最后一次提交为准。

请使用Markdown格式记录你的答案,【所有问题均为非必答】。答题时请给你的答案标明题号,不用复制题干。

题目的难度并非是递增的。如果你遇到了一些特别难以解决的问题,把他留到最后再做是一个很好的主意。

计算机是个很复杂的东西,所以在笔试题中遇到自己不会的题目是很正常的事情。如果你发现一道题目超出了你的能力范围,你可以在遵循下列规则的前提下,查阅相关的资料来解决它。

你可以:

  • 使用官方文档、RFC、技术大牛的原创博客等渠道获取一手知识

  • 参考上述资源的中文翻译获取二手知识

  • 观看或者阅读看起来很靠谱的成体系的教学视频或者教学网站,获取精细加工后的二手知识

  • 浏览CSDN等垃圾内容农场,试图从各种粑粑里逆向出不知道几手知识

  • 向ai询问一些内容辅助你的学习,不过对于关键部分记得多信息源核查

你不能:

  • 把题目或者题目的一部分扔给另一个人,让其帮你完成

  • 把题目或者题目的一部分扔给另一个人工智能,让其帮你完成后直接将其答案复制到答卷中

  • 在公开或私有频道里广播我们的笔试题目和自己超级聪明的题目做法

违反上述规则的人将会被取消本次招新资格。

请带上你的解题过程或是你的思考,参考资料等,过程比结果更重要。后续面试过程也可能会考察笔试相关的内容,只给出一个答案是没有意义的。

有任何问题,直接在招新群中提问即可。

笔试结束后,2天内发送结果,耐心等待即可~提交的答案如果包含图片等外部文件,请压缩一下一起提交

非技术题目#

  1. 至今为止,你有过哪些与计算机相关的的技术经历?请尽可能简略、多量的列举
  2. 在报名冰岩后,你通过阅读群文件的学习路线又进行了哪些学习呢?
  3. 你觉得现在的互联网发展的怎么样?对校园网互联网产品有什么好的想法?
  4. 你的未来规划是?(如保研、考研、考公、就业等)
  5. 你是否报名了除冰岩后端组以外的其他技术类团队/社团(如ACM、七边形、联创等)

计算机基础#

  1. 请给出下面这个树的前序,中序,后序遍历结果。如果可以,请给出任意一种语言实现的可以解决此问题的程序。

  1. 在一些后端服务中,用户需要上传一些文件到我们的服务器上。如果这个文件需要保存在后端程序运行的服务器中,则我们一般会指定一个目录用于存放用户上传的文件,并根据前端发回的文件名称写入。现在,我们有一个如下的,简化版的后端文件处理机制:

a. 后端服务(/home/bingyan/app/app.py)使用flask框架编写。当然,这个后端的维护者并没有傻到使用 —debug 选项运行生产项目;实际的运行命令为:flask run --reload

b. 该后端暴露了一个接口 POST /files/upload,可以接受 form-data 格式的文件;请求中同时需要包含参数 filename

c. 这个接口收到请求后,会向 /home/bingyan/app/files/{filename} 写入这个文件请想出一些办法,以利用一些神秘漏洞获取系统的操作权限,并解释一下这样做的道理

拓展任务:提出至少3种防护你利用的漏洞的解决方案

  1. 如果你是计科、网安或软工的学生,那么恭喜你,你大一/大二会开设一门叫散装离散数学的绝世好课。别担心(?),在这题中你只会用到这门课无数个知识点中的一个,即“关系的传递性”简单来说,对于一个关系 \cong ,如果满足 aba\cong bbcb\cong c 时必有 aca\cong c ,则称这个关系有传递性一些常见的,在数学中成立的传递关系有:等于、大于和小于

假设我们有如下的一个C语言函数(int为32位):

int cmp(const void * const pa, const void * const pb)
{
const int a = *(const int *)pa;
const int b = *(const int *)pb;
return (a - b);
}

是不是很简单?他通过减去两个数字来判断他们到底是大于,小于还是等于关系。

但神奇的是,这个函数并不具有传递性。请:

a. 构造出三个数 a,b,c,使得他们通过这个函数判断的结果为:a<b b<c a>c
b. 解释一下为什么会出现这个神奇的错误
c. 改进这个判断函数,使得其具有传递性

  1. HTTP 协议中有哪些常用的方法?这些方法分别代表什么功能?另外,HTTP 状态码以 1 到 5 开头的分别代表哪些含义?请简要说明。如果你有相关的开发经验,可以结合实际经历简单分享一下。

  2. 早年前,橙子写了一个自己的博客网站,(前后端分离架构,前端通过API与后端交互,并且后端拥有自己独立的域名。当时的橙子是个小白,而且很懒,他把后端中所有的API都设置为了Get类型,甚至包括删除博客文章的API也是Get类型并且没加任何鉴权操作(好孩子千万别学)。橙子写完网站发布了很多高质量博客,美滋滋的去打英雄联盟了,等他5连败回来发现自己的博文全部都没了!!!橙子本来就因为5连败心力憔悴,现在更是气晕了过去。请你救救橙子吧!!告诉他为什么会导致博文全部都消失呢??(不考虑他人攻击)

  3. 有一个酷酷的开发者叫橙子,他开发了一个很炫酷的小网站,名字叫Orange’s Home。由于这个项目只是个玩具项目,橙子为了赶快上线,采用了最基础的设计,使用了HTTP协议和REST API结构。不过,橙子最近迷上了英雄联盟,于是网站的安全和性能提升部分就暂时搁置了。此时,一个橙子的仇人听说了这个网站,决定趁橙子忙于游戏时对网站发动攻击。他委托了你来设计攻击方案。你的任务是:

a. 设计尽可能多的攻击方法,详细解释每种攻击的原理。b. 如果你是橙子,你会如何预防这些攻击?请详细说明你会采取的防御措施。

对于新手小白:你可能对一些攻击技术不太熟悉,Dont worry!你可以从网络基础知识开始,逐步了解一些常见的攻击手段。重要的是,展示你思考和学习的过程。你可以通过查阅资料或动手实验来更好地理解这些概念,并结合实际场景进行思考。但是提醒一下:尽可能不要使用AI工具。

  1. 你可曾听说过一种叫“短信轰炸”的攻击手段?这种攻击通过调用大量正常的发送短信接口向一个手机号发送短信,以干扰对方正常的使用。作为一个API开发者,假如你的应用中包含发送短信的接口,请想出一些办法让你的接口无法被用于短信轰炸。

  2. 假如你现在正在使用一台安装Ubuntu的电脑,但是突发奇想想尝试一下Alpine。请列举尽可能多的方案以实现这个目的,同时简单的说明每种方法的原理,并从安全性、性能、操作复杂度等方面进行比较

Golang#

  1. (多选)这是个实现求和的 add 函数,下列调用正确的是?
func add(args ...int) int {
sum := 0
for _, arg := range args {
sum += arg
}
return sum
}
  1. (单选)这段代码的运行结果是?

A: panic B: 5 C: 6 D:编译错误

package main
func main() {
c := make(chan int, 5)
c <- 5
c <- 6
close(c)
println(<-c)
}
  1. (主观题)在Go语言中,标准库中的数据结构 map 是线程不安全的。当遇到并发场景时,我们往往会使用线程安全的 sync.Map。阅读 sync.Map 的代码,试试解释一下为什么原版不安全,以及这个新的包装如何解决这些问题。

  2. (主观题)阅读下面代码,a==nil 和 b==nil 和 c==nil 的结果分别是什么?为什么?

var a []int
b := []int{}
c := make([]int, 0)
  1. (主观题)小叉刚开始学习 Golang,他写了以下这段代码,希望能够在不更改两个协程的 time.Sleep 和修改someNumber数值两部分代码的前提下,程序能够按照顺序输出以下内容:
someNumber: 1
someNumber: 2
someNumber: 3
someNumber: 4
someNumber: 5
someNumber: 6
someNumber: 7
someNumber: 8
someNumber: 9
someNumber: 10
someNumber: 11
...
someNumber: 96
someNumber: 97
someNumber: 98
someNumber: 99
someNumber: 100
Total iterations: 100

请你运行下面这段代码观察结果(显然它的输出不会和上边的一样);聪明的你是否能想出一个方案,使程序输出上述内容呢?

package main
import (
"fmt"
"math/rand"
"time"
)
var someNumber int
func main() {
someNumber = 0
totalIterations := 0
go func() {
for {
someNumber -= 1
time.Sleep(3 * time.Millisecond)
}
}()
go func() {
for {
someNumber += 2
totalIterations += 1
time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)
fmt.Println("someNumber: ", someNumber)
if someNumber >= 100 {
fmt.Println("Total iterations: ", totalIterations)
break
}
}
}()
ch := make(chan int)
<-ch
}
  1. (主观题)仓鼠的Golang知识比小叉丰富一些,他很快就写出了下面这个HTTP Server,并开心地展示给小Ray看。这段代码有问题吗?如何改进?
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
m := make(map[string]int)
r.Use(func(c *gin.Context) {
name := c.Query("name")
if name == "" || name == "hacker" {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "Invalid User",
})
return
}
c.Next()
})
r.GET("/hello", func(c *gin.Context) {
name := c.Query("name")
m[name]++
c.JSON(http.StatusOK, gin.H{
"message": "hello " + name,
})
})
r.GET("/users", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"users": m,
})
})
r.Run()
}

其它语言#

  1. 【C/CXX】你认为 C 和 C++ 语言有什么区别?C++ 是 C with STL 这种说法你觉得对吗?请简述理由。

  2. 【C/CXX】 (单选)下面是一段程序:

#include <iostream>
#include <memory>
struct A;
struct B;
struct A {
std::shared_ptr<B> pointer;
~A() {
std::cout << "A被销毁" << std::endl;
}
};
struct B {
std::shared_ptr<A> pointer;
~B() {
std::cout << "B被销毁" << std::endl;
}
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->pointer = b;
b->pointer = a;
return 0;
}

请问在该程序执行完成之后结果是以下哪一种?并说明原因

A. A,B 都被析构
B. A,B 都不被析构
C. a,b 都被析构
D. a,b 都不被析构

  1. 【C/CXX】下面是一首词:

Code block

int main() {
[](){} ();
[] {{}} ();
[[]] [] {};
[] () {{}};
{} [] () {};
{} [] {} ();
({{{}}});
{} [] {{}};
[[]] ({});
[[]] {{}};
}

神奇的是,它是可通过编译且运行的程序,怎么回事呢?

请任选其中你喜欢的几句,赏析其原理。或者随便说一点点你对相关内容的了解

  1. 【C/CXX】在使用一种新的数据结构(如矩阵)时,我们不得不为每次矩阵乘法都单独写上一个非常丑陋的for循环。聪明的你肯定能想到,定义一个接受两个矩阵作为参数,返回他们的积的函数能大大减少重复的代码。除了这个方法以外, C++\mathtt{C + + } 还有没有什么神奇的特性允许我们直接利用常见的算术符号来操作我们自定义的数据结构呢?尝试用这个方法为以下的Matrix类实现乘法(*)和流式输出(<<),并适当解释一下这样做的原理
class Matrix{
private:
std::vector<std::vector<double>> data;
size_t rows;
size_t cols;
public:
Matrix(size_t r, size_t c) : rows(r), cols(c) {
data.resize(rows, std::vector<double>(cols, 0.0));
}
Matrix(const std::vector<std::vector<double>>& values) {
rows = values.size();
cols = values[0].size();
data = values;
}
};
  1. 【Rust】可变性是Rust中一个相当重要的概念。通常我们的程序需要满足“同时只允许存在多个不可变引用或者单一可变引用”的规则。但是凡事总有例外……偶尔借用检查器笨笨的会拒绝掉正确的代码,让整个项目无法通过编译。这个时候如果我们确信自己的引用关系是正确的,可以采用“内部可变性”的特性,以一定性能损失为代价来将借用检查推迟到运行时完成。

假设:你用Rust实现了一个支持Cookies的HTTP客户端。仔细思考后你会发现,现在HTTP客户端执行GET请求的时候,需要修改自己的状态,也就是说客户端的某个部分必须是可写的!面对这种情况,通常的策略有:

A、函数签名为get(&mut self),结构体中保存Cookies的变量类型为String。 B、函数签名为get(&self),结构体中保存Cookies变量类型为RefCell<String>。 C、函数签名为get(&self),结构体中保存Cookies的变量类型为String,偷偷地使用unsafe D、你的奇思妙想设计

请选出你喜欢的一个或多个策略,并从调用者(用库的人)和实现者(写库的人)两个角度说明它的优缺点,以及它相对其他策略的优势。

  1. 【Rust】Rust编译大项目时耗时太长、编译太慢的问题非常让人恼火。人不一定每天都在写高性能、需要把锁的粒度控制到每个byte的多线程程序,却每天都要和Rust的蜗牛编译器搏斗。请你翻阅互联网,列举出常见的加速Rust编译的方法;如果你有C/C++/Rust相关经验,请标注这些加速方法分别在编译的哪些阶段起作用。

  2. 【Rust】众所周知(?),Rust中并没有纯粹的可变全局变量的概念。在进行程序的开发时,我们往往需要将一些数据(比如配置文件中读取的配置)作为全局可以访问的信息提供给各个组件,此时Rust的这个特性就会让我们很头痛。请分析:

a.为什么Rust禁止全局可变变量?可以从并发安全、内存安全等角度思考

b.我们对于这个问题通常有以下解决方案

i.在一些高级web框架(如actix)中,我们可以在创建一个HTTP服务器的时候为他包装进一些程序数据app_data。在后续的接口处理程序中,我们能以函数参数的形式访问到这些数据 ii.使用lazy_static宏创建初始化后就只读的全局变(常)量,或使用once_cell以避免使用令人眼花缭乱的宏iii.使用Mutex<T>或RwLock<T>等锁机制创建一个全局常量,并在读取/写入时获取锁

请你选择一种或几种自己喜欢方式说明其好处,并(如果有可能的话)说说其他几种方式会有什么样的问题

  1. 【Python】在Python 3.13之前,所有代码的并行执行都被一个叫“全局解释锁”(GIL)的神秘限制所束缚,导致除非使用if等过于麻烦的手段,我们很难真正写出可以并行的线程。请你:

a.使用AI、搜索引擎等工具理解一下什么是GIL,简单谈一谈他限制的到底是什么

b. 在Python 3.14后,官方提供了实验性的、去除了GIL的解释器。尝试使用这个新特性写出一个纯Python的,能够多线程执行的程序,并对比一下他在GIL-free和GIL环境下的速度差异与资源利用情况

  1. 【Python】Python中有一种叫“修饰器”的语法糖。它能够让我们在不改变原有代码的情况下,很方便的对函数的输入和输出进行修改,或在执行对应函数前进行一些操作。请阅读他的官方文档,尝试写一个简单的flask项目,使得:

a. 提供一个接口POST /register,提供用户名和密码,实现注册
b. 提供一个接口POST /login,提供用户名和密码,完成登录,换取JWT Token;token的claim中应当包含用户名
c. 提供一个接口GET /hello,要求使用修饰器实现读取并验证JWT Token,提取claim中的用户名,并返回hello {username}

操作系统/计网/数据库等#

  1. 【计网】socket可以实现通信服务,请用c语言写一组client与server,实现client向server发一句话(如“hello,冰岩!”),server响应client同样的内容。(请附上代码和运行截图)

  2. 【计网】当你用浏览器访问一个网页(比如www.baidu.com)的时候,client是谁,server又是谁?client和server之间经历了怎样的交互过程?它们和第一题的过程有什么区别?

  3. 【计网】众所周知,TCP和UDP是两种常用的网络协议。请简要描述一下他们的异同,并分别给出一个适用的场景

  4. 【操作系统】cat file.txt | grep “some text”中,|(管道)将上一个命令的输出作为下一个命令的输入,请了解原理(观看mit的6.s081),并用c语言在linux系统上,将 \star 实现同样的功能。命令格式参考./bingyanPipe “ls” ”*” “grep bingyan”(加上双引号方便字符串的识别),附上代码与运行截图。

  5. 【操作系统/编译原理】小\P把自己写好的Rust程序在AlpineLinux下成功编译成二进制,并且可以正常运行。他兴高采烈地把这个二进制传到了自己运行Ubuntu的云服务器上,但惊讶的发现号称永远不可能出现内存安全问题的Rust程序抛出了一个Segmentation Fault。请帮他分析一下为什么会出现这样的奇怪错误。

  6. 【NOSQL】MongoDB是一种常见的非关系型数据库。由于其非关系型的属性,我们无法使用如外键一类的,方便我们聚合查询的工具。不过,MongoDB的开发者为我们提供了一种叫聚合管道的操作,使我们能够在一个查询自定义外部集合信息的收集与添加,达到与外键类似的效果。

现在,我们有一个样式如下的数据库

注意:如果你需要在自建的MongoDB实例上复原这个数据库,你可能会发现MongoDB自动生成了_id字段的内容。出现这种情况时,请更改其余表格中对应的id,以形成查找关系

a. courses(课程)

_idname
507f1f77bcf86cd799439011计算机安全实用技术
507f1f77bcf86cd799439012数据结构

b. comments(评论)

_idcourse_iduser_idcontent
507f1f77bcf86cd799439013507f1f77bcf86cd799439011507f1f77bcf86cd799439016非常好课程,拯救加权
507f1f77bcf86cd799439014507f1f77bcf86cd799439011507f1f77bcf86cd799439017闭眼选
507f1f77bcf86cd799439015507f1f77bcf86cd799439012507f1f77bcf86cd799439016不好,快跑!

c.users(用户)

_idnicknameschool
507f1f77bcf86cd799439016Paul计算机科学与技术学院
507f1f77bcf86cd799439017GoForceX软件学院

d. likes(点赞)

_iduser_idcomment_id
507f1f77bcf86cd799439018507f1f77bcf86cd799439017507f1f77bcf86cd799439013
507f1f77bcf86cd799439019507f1f77bcf86cd799439016507f1f77bcf86cd799439014

你需要编写一个聚合管道,实现:

a. 以课程为主体

b. (易)使用课程的 _id 查询关联的评论,将评论信息附加到课程中,并隐藏 course_id 和 user_id 字段

c. (中)使用评论的 _id 找到对应的点赞数量,附加到评论中

d. (难)使用评论的 user_id 找到对应的用户,将用户信息中的昵称(nickname)附加到评论中,将学院(school)去除

e. (中)按照评论数量为课程降序排序

我们不一定需要在整个管道中保持数据的原有格式:在处理大量复杂嵌套时,一种常用方法是先分散为几个同名项目,进行操作后再按照名称分组

最终实现的效果为:

[
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "计算机安全实用技术",
"comments": [
{
"_id": ObjectId("507f1f77bcf86cd799439013"),
"content": "非常好课程,拯救加权",
"likes_count": 1,
"user_nickname": "Paul"
},
{
"_id": ObjectId("507f1f77bcf86cd799439014"),
"content": "闭眼选",
"likes_count": 1,
"user_nickname": "GoForceX"
}
]
},
{
"_id": ObjectId("507f1f77bcf86cd799439012"),
"name": "数据结构",
"comments": [
{
"_id": ObjectId("507f1f77bcf86cd799439015"),
"content": "不好,快跑!",
"likes_count": 0,
"user_nickname": "Paul"
}
]
}
]
  1. 【SQL】橙子有一天突然变成了一个小论坛的维护成员,他的boss让他做一个炫酷的用户活跃度分析,其逻辑是用户给热度很高的文章点过的赞越多,则这个用户越活跃。但是你也知道,橙子忙着青训,于是根本就没有时间写这样的东东!!于是橙子想了个办法:竞出所有给点赞数量前十的文章点过赞的用户,用这种办法来糊弄他的boss(好孩子千万别学,会被优化的)。你需要帮橙子完成这个任务!!请用一个Select语句完成这个任务。这个论坛的数据库表格简化后如下:

这个论坛的数据库表格简化后如下:

a.Users(用户表):

idname
1橙子1号
2橙子2号
3橙子3号
…………

b.Passages(文章表):

idpassageTitle
1怎么找到女朋友
2怎么找到男朋友
3怎么找到朋友
…………

c.Likes(点赞表):

idpassageduserId
112
236
367
………………

额外任务:#

注意:此额外任务不需要必做,不做也不会给你扣分的,如果你做了,或者写下了你的思考,这会是你的加分项。并且此题很麻烦,难度较高,耗时较多,可以在你全写完了,没事做的时候来试试看。

任务详情:可恶的boss发现了橙子干的好事,但是boss决定给橙子一个机会,让他再次实现这个功能,要求如下:

还是上面的三张表,找出前5名最活跃的用户,他们满足以下条件:

a. 点赞数量在前 20%20\% 的用户中
b. 他们点赞的文章的平均点赞数排名前10
c. 他们至少点赞了5篇不同的文章
d. 结果需要显示用户ID、用户名、他们的点赞数、他们点赞的文章的平均点赞数,以及他们在所有用户中的点赞数排名

橙子这次决定好好实现这个功能,但是倔强的他还是决定只使用一个SELECT语句实现这个功能!请你帮帮他编写这个SQL语句!

工具和命令#

  1. 【shell】程序组遇到了一个棘手的问题,我们想在Ubuntu20.04服务器上运行./bingyan,但是遇到了一个糟糕的报错:bash:./bingyan:Permission denied,你结合所学,排查出问题所在,并且让文件成功运行。(请给出使用的相关命令和解决的思路,我们希望你能对每个命令的输出都有所解释)

  2. 【git】程序组遇到了一个棘手的bug,为了调试在代码中添加了一些调试语句,并且存在于bugFix分支的提交记录中。终于,这个bug被解决了,此时需要把bugFix分支合并回main分支,请选择你认为尽可能好的方式(例如,你可以选择直接合并,但是会导致main分支被调试语句污染),写出需要的命令。(C0,C1代表md5值,*为当前所在分支)

  1. 【nginx】请讲述一下 nginx 的工作原理,它是如何提高性能处理大量的请求,并分发到后端的。(包括但不限于 epoll、worker、负载均衡等,请分别简述各个的原理)

  2. 【docker】程序组的服务器上运行着一个庞大的容器镜像 backend:1.2.1,这个容器的 NAME 是 Backend。现在这个容器提供的服务无法正常访问了,也没有人知道这个容器当初是通过什么命令启动的,如果是你,你会通过哪些方法和命令进行排查?

  3. 【network】假如你曾经使用过 Azure/AWS 等国际云服务商的的海外服务器,你通常会发现连接他们的延迟和速度远远慢于你使用的一些神奇的上网工具。尝试用一些常用的网络分析程序解析一下为什么虽然都在美国,但访问 89.208.246.192 的延迟比访问 13.52.0.0 的低

  4. 【Kubernetes】在 k8s 中,我们经常会遇到 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)两个概念。他们之间的关系到底是如何?我们在配置一个 workload 的持久化存储时,数据到底是存储在哪里的?谈谈你的见解

趣题#

  1. 假如你被以 100:1 的比例缩小,并被人放在了一个即将在 60 秒后启动的搅拌机里,请想出一些办法让你免于被搅碎

  2. 请你构造一段代码,使得它能同时通过 C++(GCC 10.3.1,-std=c+++11)和 FreePascal(3.0.4)的编译。

  3. 如果你实在不会做前面的题,或者做完了觉得无聊,可以试试填满下面这张图

冰岩2025秋招后端笔试题
https://www.bingyan.net/
作者
冰岩作坊
发布于
2025-09-19
许可协议
Unlicensed

部分信息可能已经过时

封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00