news 2026/10/24 8:27:24

哈工大SSE练习3实战:C语言函数级OJ刷题与调试攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
哈工大SSE练习3实战:C语言函数级OJ刷题与调试攻略

在哈工大的SSE平台上刷C语言编程练习3,算是我大一上学期最煎熬也最痛快的一段经历了。SSE是哈工大自研的在线评测系统,和国内常见的OJ平台不太一样,它不采用标准输入输出判题,而是直接调用你写的函数、检查内部逻辑和边界情况,这意味着你很难“蒙混过关”,每一行代码都得经得起推敲。练习3作为这门课的中期关卡,覆盖了数组、字符串、指针、函数递归和简单结构体,基本把C语言的核心语法犁了一遍,刷完它,你对内存和指针的理解会有一个质的飞跃。

这篇文章就是冲着这套练习去的,我会把练习3常见的题型思路、本地环境搭建、调试技巧以及我在SSE上踩过的坑全部梳理出来。不管你是正在刷SSE的在校生,还是想找一套高质量C语言练习题自学的朋友,都可以直接把这里面的方法抄过去用。

1. 认识SSE平台和练习3的考核范围

1.1 SSE是什么,和传统OJ有什么区别

很多同学第一次用SSE,都会被它“诡异”的评测方式惊到。普通的在线评测系统,比如PTA、洛谷、力扣,都是让你写一个完整的程序,从标准输入(stdin)读数据,再把结果打印到标准输出(stdout),然后和官方答案做比对。SSE不一样,它把题目拆成一个个函数签名,你只需要实现指定的函数,评测程序会直接调用你的函数,传入各种测试数据,检查函数返回值或者某个数组、结构体成员是否被正确修改。

举个例子,练习3里常有一道“字符串逆序”的题,传统OJ会给你输入一行字符串,要求你输出反转后的结果。SSE的题目则会写成:

void reverse_string(char *s);

你在这个函数内部把s指向的字符串原地反转就行,不需要printf,也不需要scanf。评测系统会自己调用这个函数,然后用strcmp去检查结果。

这个设计有一个很明显的好处:它逼着你从“写脚本”的思路切换到“设计接口”的思路。真实工程里的代码,大多数都是这种函数级别的封装和调用,而不是一个main函数走到底。所以SSE的练习虽然短小,但很接近工业界写代码的方式。坏处也很明显——很多新手搞不清楚“我到底该在哪一步输出”,或者调试时看不到中间结果,非常憋屈。这个后面我会专门讲调试方法。

1.2 练习3的知识点分布和难度曲线

从我刷过的经验来看,练习3的核心考点可以分成五块,按出现频率大致排序:

  • 字符串处理:逆序、查找子串、统计单词数、去除空格、大小写转换、敏感词过滤,占练习3的大头。
  • 数组操作:冒泡排序、选择排序、二分查找、矩阵转置、数组元素右移、进制转换。
  • 指针应用:指针传参、数组名做函数参数、指向指针的指针、动态内存分配。
  • 函数与递归:递归求阶乘/斐波那契、完数判断、最大公约数、汉诺塔。
  • 结构体与文件(少数题):学生信息排序、图书借阅记录、文件读写统计。

难度曲线很有意思,它不像有些题库那样按知识点线性递进,而是故意把简单题和难题穿插在一起。前几题往往只是让你热身,比如字符串长度、数组求和,你还没建立起警惕心,中间就会杀出来一道需要用二级指针做字符串分割的题,直接给你上一课。所以我的建议是:不要按题号顺序硬刷,先通读一遍所有题面,把会做的送分题拿稳,再去啃硬骨头。

这套练习还有一个隐藏设定——评测用例非常刁钻。它不会只测常规输入,边界值、空字符串、字符串中含有空格、超大数组、只有一个元素的数组,这些极端情况都会出现。很多同学第一遍提交,函数逻辑看着没问题,结果就是有case过不了,原因基本都出在边界条件上。

2. 常见题型拆解与解题思路

2.1 字符串处理类:逆序、统计、查找的通用解法

字符串处理的题在练习3里花样最多,但底层套路是相通的。以字符串逆序为例,最经典的思路是双指针从两端往中间走,逐个交换字符:

void reverse_string(char *s) { int left = 0; int right = strlen(s) - 1; while (left < right) { char temp = s[left]; s[left] = s[right]; s[right] = temp; left++; right--; } }

这个思路不复杂,但里面有三个细节值得较真。第一,为什么要用strlen求长度而不是自己遍历数长度?因为strlen本身就是遍历,自己再写一遍纯属重复劳动,而且容易出错。第二,为什么while条件是left < right而不是left != right?对于奇数长度的字符串,left和right最终会相遇,用!=也能停;但如果是偶数长度,比如"abcd",left最后会从1变成2,right从2变成1,两者交错而过,用!=就出问题了。第三,中途交换字符时,temp变量的类型必须是char而不是int,因为s[left]是char类型,有些编译器用int接收后在做窄化转换时可能出现符号位问题。

再比如统计单词数的题,很多人一上来就数空格个数,结果遇到连续多个空格、行首行尾空格、多个换行符夹着单词这些情况直接翻车。正确的处理逻辑是“状态转换法”——维护一个“当前是否在单词内部”的布尔状态,遍历字符串时,遇到非空格字符且当前不在单词内,就说明发现一个新单词,计数器加一,然后状态改为在单词内;遇到空格则把状态置为不在单词内。这样无论有多少连续空格,都能正确统计。

我记得练习3里还有一道“查找并替换子串”的题,那道题牵扯到数组元素的移动和动态扩容,是字符串类里比较难的。常规做法是先找到子串出现的位置,然后把它后面的所有字符整体向后移动要替换字符串长度和新旧子串长度差的距离。这里面最坑的是:移动的方向和顺序。如果是向后移动,必须从原串末尾往前逐个搬运,否则前面的字符会把后面的覆盖掉,导致数据丢失。我当年就在这里翻过车,debug到凌晨一点。

2.2 数组与排序:不只背冒泡,要理解交换的本质

练习3的数组题,大多数和排序、查找挂钩。冒泡排序是要求掌握的基本功,但SSE不会只让你“写一个冒泡排序”,它通常会包装一层:比如“对数组a的前n个元素按升序排序,并把操作次数记录下来返回”。

冒泡排序的代码谁都能背下来,但我建议你认真想一个问题:为什么外循环要跑n-1次?因为每一趟冒泡只能确定一个元素的最终位置,n个元素里,确定前n-1个的位置后,最后一个自然就位。为什么内循环的比较范围是0到n-1-i?因为每一趟结束后,最后面的i个元素已经有序,再比较它们纯属浪费。

理解了这两点,你才能应对变体题。比如有的题要求“最多进行k趟冒泡排序”,这个就要求你把外层循环的n-1改成k,然后break的判断条件也得跟着变。还有的题要求“判断某数组是否已经有序,若有序则提前返回true”,这就是在冒泡排序里加一个flag变量,如果一整趟下来没有发生任何交换,说明数组已经有序,直接退出。

二分查找也是练习3的高频考点。这里我必须强调一个很多教程不讲的细节:int mid = (left + right) / 2存在整数溢出风险。当left和right都接近int最大值时,left + right可能溢出变成负数,导致mid计算错误。安全写法是int mid = left + (right - left) / 2;。这个细节在刷练习3时体现不出来,因为测试数据不会给你这么大的数组,但到了后续课程刷更复杂的数据结构题,这几乎是必踩的坑。

排序题还有一个常被忽略的点——稳定性。如果在一次练习中,题目要求“按成绩排序,成绩相同的人保持原输入顺序”,那就不能用快速排序的裸写法,应该用插入排序或归并排序,或者在结构体里额外记录一个输入序号的字段,作为排序的次要关键字。练习3里就出现过这种题,当时班里一大半人栽在上面,因为大家默认用冒泡排序,没想过“成绩相同保持原顺序”这个要求。

2.3 指针与内存:练习3真正的分水岭

如果说练习3的前半段还在“练手”,那么从指针题开始,筛选就真正开始了。SSE的指针题设计得很讲究,它不是直接让你写一个“使用指针的字符串拷贝”,而是把指针隐藏在各种必须用指针才能解决的问题里。

最典型的是“用函数交换两个变量的值”。很多人在初步学习时知道要传指针,但遇到变体就懵了。比如题目要求“写一个函数,接受两个int指针,交换它们指向的值”,这确实简单:

void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; }

但SSE会进一步要求你“写一个函数,接受两个int指针的指针,交换这两个指针本身指向的地址”。这两个任务在概念上差着一个维度。交换指针本身的值,意味着你需要在被调函数里修改调用方传入的指针变量,让它们指向不同的内存区域,这时就必须用二级指针int **:

void swap_ptr(int **a, int **b) { int *temp = *a; *a = *b; *b = temp; }

我理解很多同学的困惑点在“为什么不直接用一级指针”?因为一级指针传参是值传递,函数内部修改形参指针本身,不会影响调用方的指针变量。想要通过函数修改传入的指针变量本身,唯一的办法就是突破一层,传入指针变量的地址,也就是二级指针。

练习3里还有一道让我印象深刻的题:“将数组a中从start位置开始的n个字符移动到数组开头”。这道题本质上涉及数组元素的大规模移动,如果不使用指针操作,代码会非常笨重。正解是用临时数组保存这n个字符,然后把剩余元素整体前移,最后把临时数组的内容接在后面。用指针表示法可以写得很简洁:

void shift_left(char *a, int len, int start, int n) { char temp[100]; for (int i = 0; i < n; i++) { temp[i] = a[start + i]; } for (int i = start + n; i < len; i++) { a[i - n] = a[i]; } for (int i = 0; i < n; i++) { a[len - n + i] = temp[i]; } }

这里最容易出错的是第二个for循环的移动方向。如果从左往右遍历并移动,当n大于1时,后面的元素会先覆盖前面的元素,导致数据错乱。正确的方向应该是从右往左,也就是从最后一个元素开始往前移动。我当时就犯了这个错,一个简单的数组移位题,我最少提交了八次才过。

2.4 递归与函数设计:把大问题拆成小问题

练习3的递归题量不算多,但几乎道道经典。完数(Perfect Number)判断、最大公约数、汉诺塔、斐波那契数列,这些题材本身并不特殊,特殊的是SSE要求你以递归方式实现,有些题还会明确禁止使用循环。

递归的核心思维在于两点:基准情形和递归表达式。拿斐波那契数列来说,基准情形是n=0时返回0,n=1时返回1,递归表达式是fib(n) = fib(n-1) + fib(n-2)。代码写出来非常短:

int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; return fib(n - 1) + fib(n - 2); }

但很多同学会被“为什么这样不会死循环”这个问题卡住。答案是:每一层递归都在向基准情形靠近,n不断减小,最终必然到达0或1,然后层层返回。写递归时必须确保参数的变化是单调收敛的,否则就是无限递归,栈溢出直接崩溃。

完数判断这道题也值得一提。完数是指一个数恰好等于它的真因子之和,比如6 = 1 + 2 + 3。用递归写因子求和的逻辑其实不太自然,因为递归通常是树状的分解过程,而因子求和是线性的扫描。我当时用一种取巧的办法:写一个递归累加函数,把扫描过程变成递归参数传递:

int sum_factors(int n, int current) { if (current >= n) return 0; if (n % current == 0) { return current + sum_factors(n, current + 1); } return sum_factors(n, current + 1); }

这样每次递归处理一个因子判断,current从2递增到n-1。这虽然不如循环直观,但确实符合递归的“基准情形 + 递归表达式”结构。同时也说明一个道理:递归不一定要从结构上拆分问题,也可以利用函数调用栈的逐层处理机制,把迭代过程重写为递归形式。

2.5 结构体与简单文件操作:练习3的压轴戏

练习3最后几道题通常会引入结构体和文件操作,跨度比较大。这类题往往给你一个结构体定义,比如学生信息包含学号、姓名、C语言成绩,然后要求你“从文件读入数据,排序后写回另一个文件”。

结构体排序的逻辑本身不难,只要会使用qsort函数或者手写冒泡排序,就能解决。但SSE对文件操作的考察有一个特点:头文件必须加对,而且FILE指针的空判断不能省略。

#include <stdio.h> typedef struct { int id; char name[20]; int score; } Student;

文件操作的标准模板大概是这样的:

int load_students(const char *filename, Student *students, int max_count) { FILE *fp = fopen(filename, "r"); if (fp == NULL) return -1; int count = 0; while (count < max_count && fscanf(fp, "%d %s %d", &students[count].id, students[count].name, &students[count].score) == 3) { count++; } fclose(fp); return count; }

这个函数有几个细节必须强调。第一,fopen返回的指针一定要判断是否等于NULL,如果文件不存在,直接使用这个指针会段错误。第二,fscanf的循环条件里同时包含count < max_count的判断,防止读入的数据量超过数组容量,这是缓冲区溢出的基本防护。第三,fscanf的返回值必须检查,如果它返回的不是3,说明读取失败或遇到文件末尾,不能再继续读。

写入文件的函数思路同理,fopen后要先判断fp是否为空,写完后fclose。我见过很多同学在调这类题的时候,明明逻辑都对,但评测就是报错,后来发现是文件命名错了,或者没有把文件放在SSE指定的相对路径下。SSE里的文件操作题,一般会明确告诉你文件的路径是相对路径还是绝对路径,记得仔细看题面。

3. 实操过程:从本地调试到通过评测的关键步骤

3.1 本地编译环境搭建与配置

虽然SSE是网页在线提交,但我不建议直接在网页里写代码——你没有调试手段,出错只能干瞪眼。我强烈建议在本地搭一个跟SSE兼容的C语言环境,把题先本地调通,再提交到SSE。

本地环境的搭建非常简单,推荐三件套:VSCode + GCC + Code Runner插件。

  • 下载并安装VSCode,这是主力编辑器。
  • 安装MinGW-w64或者TDM-GCC,配置GCC编译器,确保gcc命令在终端里可用。
  • 在VSCode扩展商店搜索“C/C++”(微软官方插件)和“Code Runner”插件,前者提供语法高亮和智能提示,后者让你能一键运行当前代码。

装好后,随便写一个main函数测试一下,按Ctrl+Alt+N(Windows快捷键),如果能正确输出结果,环境就没问题。

这里有个SSE特有的坑需要注意:SSE的题让你写的是函数,不是完整程序。本地调试时,你需要自己在下面垫一个main函数,手动构造测试数据来调用这个函数,看结果对不对。交到SSE上的时候,只交函数本体,不要带main函数。很多同学第一次交题失败,就是因为把main函数一起交上去了,SSE编译报错redefinition of 'main'。我在本地一般这样组织代码:

#include <stdio.h> #include <string.h> // 题目要求实现的函数 void reverse_string(char *s) { // ... } // 本地测试用的main函数,提交时删除 int main() { char test[] = "hello"; reverse_string(test); printf("%s\n", test); return 0; }

3.2 本地模拟SSE评测的方法

SSE评测程序的逻辑是“输入若干组数据,调用你的函数,检查结果”。本地调试时,最有效的方式不再是printf打印中间值,而是写断言(assert)来验证函数行为。我推荐你自己写一个简易测试框架,把题目给的示例输入转成测试用例:

#include <assert.h> int main() { char test1[] = "hello"; reverse_string(test1); assert(strcmp(test1, "olleh") == 0); char test2[] = "a"; reverse_string(test2); assert(strcmp(test2, "a") == 0); char test3[] = ""; reverse_string(test3); assert(strcmp(test3, "") == 0); printf("All tests passed.\n"); return 0; }

assert的好处是,一旦某个用例失败,程序会直接崩溃并打印出错行的行号和具体条件,你立刻就能定位问题。比肉眼盯着printf的输出高效太多了。我后来刷练习3,几乎每个函数都配套这么一套测试用例,养成这个习惯之后,我的提交一次通过率高了很多。

3.3 提交前必做的边界检查和代码整理

本地调试通过并不代表SSE就能通过。提交前,我习惯做一遍系统检查,把常见的低错全部扫一遍:

  • 检查所有数组下标,特别是弹栈和for循环的边界。C语言不会帮你检查越界,数组越界是“未定义行为”,有时候结果看起来正常,但审计的内存已经被污染了,非常危险。
  • 检查函数签名是否与题目完全一致。SSE的评测程序是编译后直接链接你的函数,如果函数名或参数类型不同,链接会失败。
  • 检查是否有printf或scanf残留在代码里。SSE在评测时不会读你的标准输出,但也不会阻止你打印,打印小量内容不影响结果,但大量无关输出可能拖慢评测,甚至触发输出限制报错。
  • 检查malloc分配的内存是否有对应的free。SSE内存泄漏检测可能不严格,但作为职业习惯,自己管理的内存必须自己释放。

另外,SSE编译器通常默认使用C99标准,支持变长数组VLA和单行注释,但最好别依赖某些编译器独有的扩展语法。我在练习3中用过一种其他编译器不支持的声明,结果在SSE上报了编译错误,后来发现是数组初始化语法不兼容,改成基本写法就好了。尽量写标准C,不依赖特定编译器。

4. 高频踩坑与排查技巧实录

4.1 字符串处理中的缓冲区泄漏

练习3的字符串题有一个高频bug:用scanf配合%s读取字符串时,遇到带空格的测试用例就崩了。这不是SSE的问题,是scanf本身的设计局限:%s在遇到空白字符(空格、换行、制表符)时会停止读取。

解决方法是使用fgets或者scanf("%[^\n]", str)这种格式。比如:

char buffer[128]; fgets(buffer, sizeof(buffer), stdin); // 去掉末尾的换行符 buffer[strcspn(buffer, "\n")] = '\0';

但要特别注意,SSE的题如果要求你在函数内部读取数据,往往数据不是从标准输入来的,而是作为参数传进来的。这种情况你就不要用scanf了,直接用传入的字符串即可。要是题目真的要求读输入,建议看清楚是哪个流、什么格式,再决定用哪种读取方式。

4.2 数组和指针的越界访问

有一道题我记得很清楚,是判断一个字符串中括号是否匹配。我最初用了一个固定大小的char栈来模拟括号栈:

char stack[100]; int top = -1;

当中间过程超过100层嵌套时,栈溢出直接写坏内存。这种题最稳妥的做法是用动态数组(malloc),根据字符串长度来确定栈的容量,或者至少把栈开得足够大,并时刻检查top是否越界。

指针越界更隐蔽。比如用指针遍历数组时:

while (*p != '\0') { p++; }

你确实会停在结尾,但前提是字符串确实以'\0'结尾。如果传入的是一个没有分配'\0'结尾的char数组,这个循环就会一直走下去,直到访问到不可读的地址,然后段错误。我自己就在本地遇到过“程序没报错,但输出多了几个乱码字符”的情况——原因就是数组末尾没有手动补'\0',打印时越读到相邻内存的数据。

4.3 递归导致栈溢出的异常情况

练习3的递归题,如果让你求Fibonacci数列的第n项,但n可能直接给到50,你要是用朴素递归fib(n) = fib(n-1) + fib(n-2),计算复杂度是O(2^n),估计评测程序会直接超时。这个时候要么改写成循环,要么用“记忆化搜索”(用一个辅助数组缓存已经算过的值)。

int fib_memo(int n, int *memo) { if (n == 0 || n == 1) return n; if (memo[n] != -1) return memo[n]; memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo); return memo[n]; }

这个函数相比朴素版本,每个n只会被计算一次,复杂度降到O(n),代价是额外O(n)的空间。如果递归调用的深度本身就很深,比如计算10000的阶乘,每层递归都会占用新的栈帧,极有可能栈溢出。把递归改成迭代,或者用自定义栈来模拟递归过程,是彻底的解法。

4.4 SSE平台提交时的格式与约定

SSE平台有一个让人特别容易爆发的点——它对输出格式的要求非常苛刻,哪怕多一个空格、少一个换行都算错误。如果题目要求输出“Case 1: 10”,那你的输出必须是完全一致的格式,连大小写都不能错。

检查格式的方法是把SSE给的示例输出原样复制到本地,和自己的输出做逐字符比对。有些编辑器支持“显示空格和制表符”的功能,可以把空格和Tab区别显示出来,这能帮你发现肉眼漏掉的差异。

另外,SSE有些题要求你提交整个文件,有些题要求你只提交函数体,还有些题要求你提交一个包含多个函数的.c文件。提交之前一定把这些约定看清楚。我见过不少同学,函数写得完全正确,但因为没有遵守“文件名必须是main.c”或者“开头必须包含某个特定头文件”的规则,直接判0分。

5. 完成练习3后的能力提升与延伸方向

5.1 做完练习3,你的能力会有什么变化

如果把C语言的技能树比作一棵树,练习3做扎实了,你这棵树的树干算是立住了。具体而言,你会获得三个明显的提升:

第一,你开始敢碰指针了。很多初学者对指针的恐惧源于“只看到声明,不知道它到底存了什么”。练习3的强约束——你必须通过指针去修改调用方的数据,绕不开——迫使你一遍遍理清“指针存地址,解引用访问目标”这条主线。刷完这套题,看到int **你不会再头皮发麻,而会条件反射般地思考“这破玩意儿到底是为了改哪个指针”。

第二,你建立了“边界意识”。练习3那刁钻的测试用例,天天逼着你考虑strlen返回0怎么办、数组只有1个元素怎么办、输入包含空格怎么办。这种在写代码前就把边界情况画在纸上的习惯,是刷其他OJ题和以后写工程项目最重要的防身技能。

第三,你明白了“函数接口”的意义。SSE让你写函数,评测程序负责调用,这个过程模拟了真实项目的协作模式:别人定义了接口,你来实现,实现的时候你无权改动接口,只能严格遵守约定。这种约束感,是那些自由发挥型练习给不了的。

5.2 刷完练习3之后可以往哪些方向走

如果你把练习3完整刷透了,接下来可以根据自己的目标选择进阶方向:

  • 如果你想继续刷C语言的题,推荐把PTA乙级(也就是PAT Basic Level)刷一遍。PTA的题型和SSE练习3有一定重叠,但PTA是标准输入输出判题,可以帮你把“函数实现能力”和“完整程序能力”串起来。
  • 如果你想往算法方向走,可以开始刷LeetCode简单难度的C语言题。LeetCode的题更注重数据结构应用和算法优化,和SSE纯C语言基本功的路子互为补充。
  • 如果你想深入C语言的底层机制,建议学一下GDB调试工具。练习3很多逻辑错误,其实用GDB单步跟踪几行就能定位。我后续单独写过一篇用GDB调试C程序的实操记录,有空贴出来。

还有一个小建议:把练习3你觉得写得最痛苦的那几道题,重新用不同的方法实现一遍。比如字符串逆序,除了双指针,你还可以练练递归写法、栈后进先出写法。重复实现同一道题,是巩固语法肌肉记忆非常有效的办法。

我个人刷完这套练习3,最大的体会是:C语言不是看会的,也不是听课听会的,是一道题一道题“喂”出来的。SSE的评分系统虽然冷酷,但正是这种“不过就是不过、没有任何解释余地”的冷酷,逼着我把每一段代码都弄到真正能工整运行的程度。希望这篇文章能帮你在SSE的练习3里少绕几个弯。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 8:26:40

哈工大SSE平台C语言练习3备考指南:数组、字符串与指针全解析

如果你是哈工大软件学院或计算机相关专业的新生&#xff0c;第一次打开SSE平台&#xff0c;看到“C语言编程练习3”这个练习名称&#xff0c;心情大概很复杂——前两次练手还停留在printf("Hello World")和简单分支循环&#xff0c;突然题目列表里出现了数组、字符串…

作者头像 李华
网站建设 2026/10/14 11:11:45

金融信贷贷前初审AI智能体实战:AgentArts工作流编排与落地全记录

前段时间我一直在和华为云智果 AgentArts 死磕一件事&#xff1a;把金融信贷场景里的贷前初审流程&#xff0c;从人工填表、人工翻材料&#xff0c;改造成一个真正能跑的AI智能体。起因很现实——一条消费信贷产品线的申请量翻了一倍之后&#xff0c;初审团队已经忙到需要周末加…

作者头像 李华
网站建设 2026/10/23 5:50:38

昇腾AI基建六件套:TileLang与FlashMLA技术解析

1. 项目概述&#xff1a;一场被误读为“破壁”的底层基建重构“拆英伟达的墙&#xff0c;从架空地基开始”——这个标题里没有一句虚话&#xff0c;但几乎每一句都容易被断章取义。我盯着它看了三天&#xff0c;不是在琢磨怎么“打倒谁”&#xff0c;而是在反复确认&#xff1a…

作者头像 李华
网站建设 2026/10/16 6:25:08

大模型评测体系搭建全攻略:从能力维度到落地避坑

大模型评测这事儿&#xff0c;看着是跑几个榜单、算几个分数&#xff0c;实际上水很深。外行看热闹&#xff0c;觉得跑个MMLU、刷个榜单就是评测了&#xff1b;内行都知道&#xff0c;评测体系的设计直接决定你手上的模型到底能不能用、值不值得上线。我从做大模型应用落地和模…

作者头像 李华
网站建设 2026/10/14 11:11:48

DDD的“岁月史书”:警惕那些“本来应该”的伪定义

最近我在几个技术群和博客评论区里&#xff0c;看到了一波很有意思的“回头翻案”式言论。有人翻出十二年前的帖子&#xff0c;说“DDD本来就是给遗留系统改造用的&#xff0c;你们拿来设计新系统是误用”&#xff1b;有人说“DDD根本不是什么建模方法&#xff0c;它只是分层架…

作者头像 李华
网站建设 2026/10/19 18:56:22

企业级疫苗预约系统落地实践:SpringBoot+Vue+MyBatis+MySQL

企业级疫苗发布与接种预约系统的落地实践做这个项目之前&#xff0c;我被疫苗预约这个场景折磨过一阵子。社区卫生院的朋友跟我吐槽&#xff0c;每到流感季或者新疫苗到货&#xff0c;电话被打爆、现场排长队、库存对不上&#xff0c;光靠Excel登记根本撑不住。聊完我就明白&am…

作者头像 李华