商汤C/算法校招笔试题复盘:指针、位运算与内存对齐考点拆解
1. 从一道校招题看C/算法岗的筛选逻辑2018年前后那几年计算机视觉和深度学习方向正处于大规模扩张期各家做AI的公司都在抢人校招笔试自然成了第一道筛子。商汤那年的C/算法笔试题在圈子里流传挺广我后来陆续跟几个当年参加过这场笔试的人聊过也自己拿这套题做过复盘。说实话这套题放到今天看依然有参考价值因为它考的不是死记硬背而是你对C语言底层细节和基础算法的手感。很多人一听到算法岗笔试就默认全是LeetCode那套动态规划、图论其实那年的卷子结构挺有意思C语言基础题占了相当比例指针、内存布局、位运算这些老派内容反复出现算法部分反而更偏向数组操作、字符串处理和简单的递归/迭代转换。这个配比背后是有逻辑的——做底层算子优化、模型部署、推理引擎的人C功底不过关根本没法干活。你写得出快速排序但搞不清指针和数组的区别在实际工程里是要出事的。这篇文章我打算把这套题的几个典型考点拆开讲透不是给你一份标准答案就完事而是把每道题背后面试官到底想筛掉什么人讲清楚。适合准备C/C方向校招的应届生也适合工作几年但想回头补一补底层基础的开发者。我会补充一些当年题目里没写、但实际面试中经常追问的延伸点以及我自己踩过的坑。2. 指针与数组的边界题最容易翻车的第一道坎2.1 为什么这类题几乎年年出现C语言笔试卷子里指针和数组的关系是永恒的开场题。当年那套题里有一道很典型的给一段涉及数组名、指针运算、sizeof和strlen混用的代码让你判断输出。这类题看着简单但正确率一直不高原因在于大部分人学C的时候是背结论而不是理解内存。我先把核心结论摆出来但更重要的是理解它为什么成立。数组名在大多数表达式里会退化成指向首元素的指针但它本身不是指针——它是一个数组类型的对象。这个区别在sizeof和取地址两种场景下会暴露出来。sizeof(数组名)得到的是整个数组占用的字节数而sizeof(指针)得到的是指针本身的大小32位系统4字节64位系统8字节。很多人栽就栽在这里。int arr[10]; int *p arr; printf(%zu\n, sizeof(arr)); // 40整个数组 printf(%zu\n, sizeof(p)); // 8指针本身64位 printf(%zu\n, sizeof(arr) / sizeof(arr[0])); // 10元素个数注意sizeof是编译期运算符不是函数。它不会对表达式求值所以sizeof(arr)里的arr根本不会执行。这个点在笔试题里被反复利用来设陷阱。2.2 指针运算的步长问题指针加减整数时移动的步长是所指类型的大小不是字节数。int *p做p1地址实际增加4字节char *p做p1地址增加1字节。当年有道题给了一个int数组和一个指向它的指针让你算p1和(char*)p1分别指向哪里本质就是考这个步长概念。我见过太多人在这里出错因为他们脑子里把指针当成地址数字在算而忽略了类型信息。正确的思维模型是指针 地址 类型。类型决定了它一次能跨多远也决定了解引用时读几个字节。再延伸一个高频追问a和a的区别。假设int a[5]a退化后是int*a是int(*)[5]两者数值相同但类型不同a1跨4字节a1跨20字节。这个点在实际写代码时很少用到但面试官特别爱问因为它能瞬间区分出真懂和背过的人。2.3 二维数组传参的经典陷阱二维数组作为函数参数时第二维的长度不能省略。void f(int a[][5])合法void f(int a[][])非法。原因是编译器需要知道每一行有多长才能正确计算a[i][j]的地址。这个知识点在当年那套题里以找错的形式出现让你指出函数声明哪里有问题。我在实际项目里也踩过这个坑。早期写图像处理代码时想把一个二维像素数组传给处理函数图省事写成了int **结果运行直接崩。因为二维数组在内存里是连续的一块而int **是指针的指针两者内存布局完全不同。正确做法要么用int (*p)[WIDTH]要么干脆退化成一维数组加手动索引data[i * WIDTH j]。后者在性能敏感的场合反而更常见因为编译器优化起来更友好。3. 位运算与内存对齐区分会用C和懂C的分水岭3.1 位运算题的套路与实战价值那套题里位运算部分有几道很经典的判断一个数是不是2的幂、统计二进制中1的个数、不用临时变量交换两个数。这些题现在网上烂大街了但当年做出来的人不多因为很多人对位运算不熟。判断2的幂标准解法是n 0 (n (n - 1)) 0。原理是2的幂的二进制只有一个1减1之后那个1变成0、后面全变1两者按位与必然为0。这个技巧在实际工程里用得很多比如哈希表扩容时判断容量、内存池按2的幂对齐分配。统计1的个数n (n - 1)能消掉最低位的1循环几次就有几个1。比逐位检查快因为循环次数等于1的个数而不是总位数。还有个更骚的解法是查表法把8位的结果预先算好存数组然后按字节查适合对性能极致要求的场景。int count_ones(unsigned int n) { int count 0; while (n) { n (n - 1); count; } return count; }提示写位运算时一定要用无符号类型。有符号数的右移行为是实现定义的算术右移还是逻辑右移取决于编译器而且负数做位运算容易出意外。这是当年题目里一个隐藏的坑。3.2 内存对齐笔试爱考、工程更要命内存对齐是C语言里课本讲得少、实际用得多的典型。当年有道题给一个结构体让你算sizeof里面故意混了char、int、double考的就是对齐规则。规则本身不复杂每个成员的偏移量必须是它自身大小的整数倍在默认对齐下结构体总大小必须是最大成员大小的整数倍。但实际算起来容易乱。我一般用画格子的方法从偏移0开始每个成员先对齐再占位最后整体补齐。struct S { char a; // 偏移0占1字节 // 填充3字节 int b; // 偏移4占4字节 char c; // 偏移8占1字节 // 填充7字节 double d; // 偏移16占8字节 }; // 总大小24为什么要有对齐因为CPU访问内存是按字word来的不对齐的话一个变量可能横跨两个内存块需要两次访问再拼接性能差。有些架构比如某些ARM甚至直接不允许非对齐访问会触发硬件异常。实际工程里的经验结构体成员按大小从大到小排列能减少填充字节。上面那个结构体如果改成double d; int b; char a; char c;大小能压到16字节。这个技巧在写网络协议包、文件格式解析时特别有用因为你要精确控制每个字节的位置。我做过一个二进制协议解析的项目结构体没排好序多出来的填充字节导致解析错位排查了大半天才定位到。3.3 大小端判断与联合体的妙用判断机器是大端还是小端经典写法是用联合体int is_little_endian() { union { int i; char c; } u; u.i 1; return u.c 1; }联合体的所有成员共享同一块内存给i赋值1后如果最低地址的字节是1说明是小端。这个技巧当年也考过。大小端在网络编程里是绕不开的跨平台传输数据必须统一字节序通常约定用大端网络字节序发送前用htonl、htons转换。4. 算法题拆解数组、字符串与递归的实战变形4.1 数组类题目的原地操作思路算法部分那套题偏向基础没有特别刁钻的。有一道是原地删除数组中指定元素要求空间复杂度O(1)。标准解法是双指针一个快指针遍历一个慢指针记录有效位置遇到不等于目标值的就写到慢指针位置。int remove_element(int *nums, int n, int val) { int slow 0; for (int fast 0; fast n; fast) { if (nums[fast] ! val) { nums[slow] nums[fast]; } } return slow; }这类原地题的核心思想是不要新建数组用读写指针在原数组上覆盖。这个模式在图像处理里很常见比如原地做像素值的阈值过滤避免额外分配内存。我做过一个实时视频处理的项目每帧都新建缓冲区的话内存分配开销扛不住必须原地操作。4.2 字符串处理的边界条件字符串题最容易在边界上翻车空串、只有空格、全是同一个字符、超长串。当年有道题是反转字符串里的单词比如hello world变成world hello。思路是先整体反转再逐个单词反转。void reverse(char *s, int l, int r) { while (l r) { char t s[l]; s[l] s[r]; s[r] t; l; r--; } } void reverse_words(char *s) { int n strlen(s); reverse(s, 0, n - 1); int start 0; for (int i 0; i n; i) { if (s[i] || s[i] \0) { reverse(s, start, i - 1); start i 1; } } }注意处理字符串时永远要问自己如果输入是空串会怎样如果末尾没有空格会怎样。我见过太多代码在i n和i n之间搞错导致最后一个单词没被处理或者越界访问。4.3 递归转迭代面试官最爱追问的延伸那套题里有一道递归题具体记不太清了但面试环节经常追问能不能改成迭代。递归转迭代是C/算法岗的高频考点因为递归有栈溢出风险工程代码里能迭代就迭代。以斐波那契为例朴素递归是指数级复杂度改成迭代就是O(n)long fib(int n) { if (n 2) return n; long a 0, b 1; for (int i 2; i n; i) { long c a b; a b; b c; } return b; }更一般的情况递归转迭代需要自己用栈模拟调用过程。比如二叉树的中序遍历递归写法三行搞定迭代写法要手动维护一个栈。这个转换能力能体现你对函数调用栈的理解深度面试官很看重。5. 复盘这套题当年考生最容易丢分的几个点5.1 眼高手低算法会写C基础题反而错我聊过的几个人里有个共同现象刷了几百道LeetCode结果C基础题错一片。原因很简单LeetCode用的是高级语言的抽象你不需要关心内存、指针、对齐这些。但C/算法岗的笔试恰恰要考这些底层细节因为岗位本身就是要跟底层打交道。我的建议是准备这类岗位时专门花时间过一遍《C专家编程》和《深入理解计算机系统》里关于指针、内存、链接的章节。不用全看挑指针、数组、结构体对齐、位运算这几块精读。这些内容在笔试里性价比极高投入产出比远超再刷50道动态规划。5.2 忽略编译期与运行期的区别sizeof、宏展开、const、static这些概念很多人在编译期还是运行期上犯迷糊。比如sizeof是编译期求值宏是预处理期文本替换const变量在C里其实还是运行期的C里才更多体现编译期常量。这些区别在笔试题里经常被拿来设陷阱。举个典型例子#define SQUARE(x) x*x调用SQUARE(12)得到的是12*12 5而不是9。因为宏是文本替换没有括号保护。正确写法是#define SQUARE(x) ((x)*(x))。这个坑我当年也踩过后来写宏一律给参数和整体都加括号。5.3 时间分配失衡那套题题量不小很多人前面C基础题磨太久后面算法题没时间写。合理的策略是先扫一遍全卷把有把握的快速拿下卡壳的先跳过。C基础题如果30秒内没思路大概率是想偏了先标记跳过。算法题哪怕写不出最优解也要把暴力解写出来拿部分分。我个人的经验是笔试和实际写代码是两回事。笔试考的是在压力下快速调用知识储备所以平时练习一定要计时。我当年准备的时候每周掐时间做两套完整卷子模拟真实考场节奏效果比零散刷题好得多。6. 从这套题延伸到今天的准备策略6.1 底层功底依然是硬通货虽然现在AI岗很多转向了Python和框架层面但做推理优化、算子开发、嵌入式部署的方向C功底依然是硬门槛。那套2018年的题放到今天考点几乎没变因为底层的东西变化慢。指针、内存、位运算、对齐这些十年后还是这些。如果你目标是这类岗位我的建议是别只盯着刷题网站。找一本讲C底层的书配合实际写点小项目——比如手写一个内存池、实现一个简单的哈希表、做个位图。写的过程中你会自然遇到对齐、指针运算、内存管理这些问题比单纯做题理解深得多。6.2 算法部分要抓变形能力基础算法就那些但笔试和面试考的是变形。同一道两数之和可以变成三数之和最接近的两数之和有序数组的两数之和。核心是理解双指针、哈希、排序这些工具的适用场景而不是背题。我习惯的做法是每做完一道题问自己三个问题这题的暴力解是什么优化点在哪如果条件变一下比如数组变成链表、有序变成无序该怎么改这三个问题想清楚一道题顶十道。6.3 笔试之外的准备笔试只是第一关后面还有面试。那套题对应的面试环节据我了解会追问项目细节、手写代码、现场分析问题。所以准备笔试的同时别忽略项目梳理和表达能力。我见过笔试满分但面试讲不清自己项目的人一样被刷。具体来说把你做过的项目按背景-难点-方案-结果四段式整理好每个项目准备一个能讲三分钟的故事。手写代码部分重点练数组、字符串、链表、二叉树这几类因为面试现场写代码时间紧这些是最常考的。最后分享一个我自己的小习惯每次做完一套笔试卷不管对错都把错题和卡壳的题整理到一个文档里标注错因和正确思路。考前一周只看这个文档比重新刷题效率高得多。这个习惯我从准备校招一直保持到现在工作后排查线上问题也靠类似的复盘文档积累经验。

相关新闻

QML动态创建组件:Loader、createObject与Instantiator选型指南

QML动态创建组件:Loader、createObject与Instantiator选型指南

1. 动态创建组件到底在解决什么问题QML 里写界面,最顺手的方式当然是直接在.qml文件里把组件摆好,静态声明、层级清晰、所见即所得。但实际项目做久了就会发现,静态声明只能覆盖“结构固定”的场景。一旦界面需要根据数据量、用户操作或者运行…

2026/10/12 20:17:32 阅读更多 →
GitHub 新晋“镇站之宝”:用一套死板的流程,治好了我的 AI 编程焦虑——TaoToken 统一 Key 接入 Agentic Skills Framework 实战

GitHub 新晋“镇站之宝”:用一套死板的流程,治好了我的 AI 编程焦虑——TaoToken 统一 Key 接入 Agentic Skills Framework 实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 20:17:32 阅读更多 →
Python异常处理三件套:try/except/finally的契约式设计

Python异常处理三件套:try/except/finally的契约式设计

1. 为什么“写完try就跑”是Python里最危险的惯性操作我见过太多人把try/except当成万能创可贴——函数一报错,CtrlC/V三行代码往里一塞,程序不崩了,就以为万事大吉。某次参与一个数据清洗脚本的代码评审,发现一段核心逻辑里嵌着这…

2026/10/12 20:16:31 阅读更多 →

最新新闻

SkiaSharp 维护指南:从 Skia 上游同步到 .NET 绑定的发布全流程

SkiaSharp 维护指南:从 Skia 上游同步到 .NET 绑定的发布全流程

图形学图像处理跨平台 【免费下载链接】SkiaSharp SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Googles Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render i…

2026/10/12 22:07:23 阅读更多 →
35个GitHub热门Claude Code技能实测:把settings改到TaoToken后AI编程效率翻倍

35个GitHub热门Claude Code技能实测:把settings改到TaoToken后AI编程效率翻倍

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 22:07:22 阅读更多 →
YOLOv5 6.1全中文注释包:从源码解析到自定义训练与部署

YOLOv5 6.1全中文注释包:从源码解析到自定义训练与部署

简介:这份资源是YOLOV5 6.1版本的全中文注释代码压缩包,面向目标检测方向的研究生、参加创新创业大赛的学生以及刚接触物体识别项目的开发者,主要解决官方源码注释稀少、初学者难以读懂网络结构与训练流程的问题。压缩包共约2000个文件&#…

2026/10/12 22:07:22 阅读更多 →
飞鸟数据集全流程实战:从VOC标签转换到YOLOv8训练与调优

飞鸟数据集全流程实战:从VOC标签转换到YOLOv8训练与调优

简介:飞鸟数据集是一套面向目标检测任务的鸟类图像资源,适合计算机视觉初学者、算法研究者以及无人机监控、野生动物保护等应用方向的开发者,也适用于课程设计与科研实验。数据涵盖近景个体、飞翔姿态与群鸟场景,覆盖树上、城市等…

2026/10/12 22:07:22 阅读更多 →
Windows上运行iOS模拟器:三条靠谱路线与避坑指南

Windows上运行iOS模拟器:三条靠谱路线与避坑指南

简介:对于想在Windows(含Windows 7)电脑上运行苹果iOS系统、体验iPad类应用的普通用户和开发者,这份资源提供了一条无需购买真实苹果设备的替代路径。模拟器本质上是通过软件在异平台模拟另一个系统环境,因此资源不仅介…

2026/10/12 22:07:22 阅读更多 →
Android 广播 - 组件通信

Android 广播 - 组件通信

一、Service 通知 Activity 更新 UI 1、Service public class BroadcastConstants {public static final String ACTION_UPDATE_UI "com.example.ACTION_UPDATE_UI";public static final String EXTRA_DATA "extra_data"; }public class MyService exten…

2026/10/12 22:06:21 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →