news 2026/10/6 4:08:54

C语言数制转换实战:栈与除基取余的完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言数制转换实战:栈与除基取余的完整实现

简介:针对初学数据结构的C语言学习者,这份资源以顺序栈为核心,演示如何将十进制数转换为八进制等任意进制,正好补足严蔚敏教材中伪代码不易直接运行的痛点,给出可直接调试的完整实例。压缩包内仅1个PDF文件,大小47KB,正文包含SqStack结构体、初始化、入栈、出栈、栈空判断以及conversion()转换函数的完整源码,并对算法3.1的执行流程逐段注解,同时呈现了动态扩容与越界处理等关键细节。已有894人学习下载,适合正在复习栈与进制转换、希望对照教材伪代码进行实操验证的读者。通过阅读PDF,可掌握利用栈后进先出特性保存余数并逆序输出结果,理解n % m入栈、n = n / m迭代更新的核心思路;若需转换为二进制或十六进制,只要修改目标进制输入m即可,能够举一反三扩展应用。

1. 数制转换实例代码:为什么数据结构课第一道栈实验题就能拦住一批人

身边不少人在第一次上机时被这道题卡住:十进制25转二进制,手算明明是11001,代码一跑却输出10011;十进制100万转二进制,结果位数少了一截;转十六进制倒是出来了,字母却是小写,考试偏偏要求大写。其实数制转换的核心就是一句「除基取余、余数入栈、出栈逆转」,十行逻辑,真正拉开分差的是边界条件、进制校验和溢出处理。这篇文章用一个可运行的C语言实例代码集合,把整数转换、小数转换、负数处理、任意进制互转和五个高频翻车场景一次说清,适合正在写数据结构实验报告、刷考研数据结构题,或者刚学完栈想找练习的人直接照着改。

2. 除基取余法完整实现:十进制转二、八、十六进制的代码与三个必调参数

除基取余是数制转换的地基,也叫「除N取余法」:十进制整数转N进制,不断用N去除目标数,记下每次的余数,最后把余数序列倒序输出。第一次除出来的余数是结果的最低位,最后一个余数是最高位。这个「后进先出」的顺序,和栈的语义完全吻合,所以数据结构与算法教材几乎都把数制转换放在栈那一章的课后题里,连《大话数据结构》讲栈的应用时也拿它当第一个例子。实际开发里,我们常用数组直接逆序输出,未必每次都建一个正经栈结构,但理解栈在这里扮演的角色,对你后面学表达式求值、递归转非递归都有帮助。

这一章给三个从简到繁的版本:数组模拟栈的最小代码、标准顺序栈接口、带字符映射的十六进制转换。你按自己实验报告的进度挑一个用。

2.1 数组模拟栈:能跑通的最小可运行版本

先看最直观的版本。一个一维数组、一个栈顶指针top,入栈就是stack[++top] = value,出栈就是return stack[top--],不需要结构体,一个stdio.h就能跑。

#include <stdio.h> #define MAX_STACK 32 // 32位int二进制最多31位,留一位给结束符/边界 int stack[MAX_STACK]; int top = -1; void push(int value) { if (top >= MAX_STACK - 1) { return; // 栈满直接丢弃,调用方自行判断 } stack[++top] = value; } int pop(void) { if (top < 0) { return -1; // 空栈返回-1,正常余数范围是0~15,不会撞 } return stack[top--]; } void decToBin(unsigned int n) { if (n == 0) { printf("0\n"); return; } while (n > 0) { push(n % 2); n /= 2; } while (top >= 0) { printf("%d", pop()); } printf("\n"); } int main(void) { decToBin(25); // 期望输出 11001 decToBin(0); // 期望输出 0 return 0; }

代码逻辑分两段:while (n > 0)负责把余数一个个压进去,第二个while (top >= 0)负责弹栈输出。中间不要混写,混写的后果就是顺序错乱,这个问题在后面避坑章节还会专门讲。这里有两个参数值得按需改:MAX_STACK和取模基数。MAX_STACK设成32,是因为32位无符号整数转二进制最多31位,转八进制最多11位,转十六进制最多8位,32足够。你要是转long long范围的大数,就把这个宏改成64或再加一位。取模基数改成8或16,printf的%d不用动,就能直接输出八进制或十六进制的数字串——因为0到15这十六个数字正好是十进制符号的子集。

这个版本的特点就是短,适合考试手写和实验报告第一版交差。缺点是top是全局变量,你在一个程序里同时跑多个转换函数,栈状态会互相串。这也是下一步引出顺序栈结构体的原因。

2.2 顺序栈接口:InitStack到DestroyStack的标准写法

数据结构实验报告通常要求体现「抽象数据类型」意识,也就是把栈的操作封装成函数集。常见做法是把栈定义成结构体,让每个调用方持有一份独立实例,下面这套接口和严蔚敏《数据结构(C语言版)》里的写法基本一致。

#include <stdio.h> #include <stdlib.h> #define STACK_INIT_SIZE 16 #define STACK_GROW_FACTOR 2 typedef struct { int *base; // 栈底指针,malloc出来的堆内存 int *top; // 栈顶指针,始终指向下一个可用位置 int capacity; // 当前容量,按元素个数计 } SqStack; void initStack(SqStack *s) { s->base = (int *)malloc(STACK_INIT_SIZE * sizeof(int)); if (!s->base) exit(EXIT_FAILURE); s->top = s->base; s->capacity = STACK_INIT_SIZE; } void push(SqStack *s, int value) { if (s->top - s->base >= s->capacity) { int *newBase = (int *)realloc(s->base, s->capacity * STACK_GROW_FACTOR * sizeof(int)); if (!newBase) exit(EXIT_FAILURE); s->base = newBase; s->top = s->base + s->capacity; // 关键:realloc后必须重算top s->capacity *= STACK_GROW_FACTOR; } *s->top++ = value; } int pop(SqStack *s) { if (s->top == s->base) { return -1; // 空栈 } return *--s->top; } void destroyStack(SqStack *s) { free(s->base); s->base = NULL; s->top = NULL; s->capacity = 0; }

这套代码的注意点有两个。第一,STACK_INIT_SIZE设成16,理由是单次十进制转二进制的余数最多31个,16不够用会自动扩容一次,不至于一直在realloc。第二,扩容后必须重新计算top:realloc可能把整块内存搬到新地址,旧指针全部失效,把top重设成新base + 旧容量,指向旧数据末尾,之后*s->top++ = value才能接着写。这是我见过动态栈最常见的野指针来源。

至于扩容因子为什么选2而不是1.5,纯属C语言的现实考虑:realloc的扩容语义由内存分配器决定,不存在「原地扩容」保证,每次扩容都可能搬运。因子越大,搬运次数越少,最坏浪费的空间越多;因子越小,空间利用率越高,但搬运越频繁。数据结构(C语言版)课程里用2倍是约定俗成,因为它实现简单、均摊复杂度容易算。

2.3 十进制转十六进制:字符映射表与大小写约定的取舍

十六进制和二进制有个本质区别:二进制余数只有0和1,直接打印数字即可;十六进制余数范围0到15,其中10到15必须映射成A到F。这时候需要一张映射表,常见做法是预定义一个字符串当查表字典。

#include <stdio.h> #include <string.h> static const char HEX_DIGITS[] = "0123456789ABCDEF"; void decToHex(unsigned int n, char *out, size_t outSize) { char tmp[11]; // 32位整数十六进制最多8位,10足够 int idx = 0; if (n == 0) { tmp[idx++] = '0'; } else { while (n > 0) { tmp[idx++] = HEX_DIGITS[n % 16]; n /= 16; } } if ((size_t)idx + 1 > outSize) { return; // 输出缓冲区不够,宁可失败也不要越界写 } for (int i = 0; i < idx; i++) { out[i] = tmp[idx - 1 - i]; // 逆序拷贝 } out[idx] = '\0'; } int main(void) { char buf[12]; decToHex(255, buf, sizeof(buf)); printf("%s\n", buf); // 期望输出 FF return 0; }

HEX_DIGITS把余数直接当下标用,比一串if-else简洁得多。这里有个独立的决策点:题目要求小写输出时,最稳的做法是把表改成"0123456789abcdef",而不是在输出阶段用tolower()统一转。因为tolower会把数字字符'0'到'9'也过一遍,结果虽然碰巧一样,逻辑上却不干净,实验报告里容易被老师划问号。如果你要同时支持大小写,就再加一个int uppercase参数,查表前判断一次。

注意:decToHex里的outSize检查不能省。实验报告里常见的问题是输出缓冲区开在栈上,函数内部不知道边界,一旦目标数超过预设位数就是越界写,轻则乱码重则段错误。宁可多写三行防御,也不要花两小时查一个内存越界。

3. 数制转换的小数与负数:乘基取整的精度控制与符号位处理

整数转换写完,实验报告第二问往往是「把十进制小数转成二进制小数」。原理叫「乘基取整」:小数部分乘以2,取出整数位作为二进制小数的第一位,剩下的小数部分继续乘2,直到小数部分归零或达到指定精度。这句话里藏着一个浮点数的黑匣子——很多初学者用while (frac != 0)判断循环结束,结果发现double里的0.1转二进制永远除不尽,程序直接死循环。这一章把小数和负数一次说透,两条都是考试和上机的常客。

3.1 乘基取整法:循环终止条件不能只靠「小数部分为0」

#include <stdio.h> void decFracToBin(double frac, int precision) { printf("0."); for (int i = 0; i < precision; i++) { frac *= 2.0; int bit = (int)frac; // 取出整数位 printf("%d", bit); frac -= (double)bit; // 保留小数部分继续乘 if (frac < 1e-12) { // 足够接近0就提前结束 break; } } printf("\n"); } int main(void) { decFracToBin(0.625, 16); // 期望输出 0.101 decFracToBin(0.1, 16); // 期望输出 0.0001100110011001... return 0; }

precision是输出精度,必须显式传入。为什么不能靠frac == 0退出?因为0.625在二进制下是精确的(0.101),它能结束是因为0.625恰好是2的负一次方加2的负二次方加2的负三次方;而0.1在二进制下是无限循环小数,double只能存近似值,永远到不了0。实际工程里小数转进制基本都限定位数,二进制给16位,八进制和十六进制给6到8位就够还原精度了。判断frac < 1e-12是因为double的机器精度大约在1e-15量级,阈值放松两个量级,既能避免死循环,又不会在还有效的小数位时提前截断。

还有一个影响输出的细节:(int)frac是向零取整,如果frac恰好在0.9999999999附近,取整后得到0,可能丢一位有效数字。严谨的做法是先frac += 1e-12再取整。我在自己代码里一般不加,因为16位精度下误差会被后面位吃掉,但如果要求输出20位以上,就得加上这个修正。

3.2 负数怎么转:符号位单独处理比补码直转更符合题意

负数转换是高频考点。最常见、最稳的做法是把符号单独拿出来,先输出一个'-',再对绝对值做除基取余。不建议把负数直接强转成无符号数再套算法,因为那样转出来的是补码的二进制表示,和数学意义上的「数制转换」是两回事,而且容易把结果搞成一大串1。

void decToBaseWithSign(long long n, int base, char *out, size_t outSize) { unsigned long long absVal; char tmp[80]; int idx = 0; int sign = 0; if (n < 0) { sign = 1; absVal = -(unsigned long long)n; // 先转无符号再取负,避免LLONG_MIN溢出 } else { absVal = (unsigned long long)n; } if (absVal == 0) { tmp[idx++] = '0'; } while (absVal > 0) { tmp[idx++] = "0123456789ABCDEF"[absVal % base]; absVal /= base; } if ((size_t)(sign + idx + 1) > outSize) { return; } int pos = 0; if (sign) { out[pos++] = '-'; } for (int i = idx - 1; i >= 0; i--) { out[pos++] = tmp[i]; } out[pos] = '\0'; }

这段代码里最值得圈出来的是一行:absVal = -(unsigned long long)n;。为什么不能直接写absVal = -n?因为当n恰好等于LLONG_MIN时,-n在long long范围内直接溢出,未定义行为,结果还是负数。必须先转成无符号型再取负,借无符号整型的回绕语义拿到正确的绝对值。这个边界值你可能一年都碰不到一次,但碰到就是查半天的疑难bug。符号位单独输出的另一个好处是代码结构清晰,实验报告里老师一眼能看到你的逻辑层次:正数负数共用转换核心,符号只是前缀。

3.3 整数与小数合一的完整转换实例:double型入参的两个精度参数

前面两节各自独立,实际实验题会要求你把它们拼成一个函数:输入一个double,输出它的二进制表示,整数部分和小数部分都要处理。

#include <stdio.h> void decToBinFull(double value, int intPrecision, int fracPrecision) { long long intPart = (long long)value; double fracPart = value - (double)intPart; if (value < 0) { printf("-"); intPart = -(long long)intPart; fracPart = -fracPart; } char tmp[64]; int idx = 0; if (intPart == 0) { tmp[idx++] = '0'; } while (intPart > 0) { tmp[idx++] = '0' + (intPart % 2); intPart /= 2; } for (int i = idx - 1; i >= 0; i--) { printf("%c", tmp[i]); } if (fracPrecision > 0) { printf("."); for (int i = 0; i < fracPrecision; i++) { fracPart *= 2.0; int bit = (int)fracPart; printf("%d", bit); fracPart -= (double)bit; if (fracPart < 1e-12) break; } } printf("\n"); } int main(void) { decToBinFull(-9.625, 32, 16); // 期望输出 -1001.101 return 0; }

这里的intPrecision其实没有参与循环控制,因为除基取余到0自然结束,不需要位数上限。真正影响输出的是fracPrecision:同样是0.1,8位精度输出0.00011001,16位输出0.0001100110011001,后者的还原误差小一到两个数量级。考试题如果写「精确到8位二进制小数」,你就传8,别多也别少。(long long)value这一步隐含了一个前提——这个函数只处理绝对值小于long long上限的数,超出部分会被截断,真遇到超大数要用后面的十进制字符串方案。

4. 任意进制互转实例代码:从字符串输入到进制校验的一条龙实现

课程设计比实验题再进一步,往往是「输入一个N进制数,转换成M进制」。这要求程序能处理字符串输入,而不只是拿内存里的整数转换。经典思路是「任意进制→十进制→任意进制」,中间用unsigned long long当桥梁。这一章的代码可以直接抄进数据结构实验报告,也可以改造成命令行小工具。它同时覆盖了多数C语言基础练习里没细讲的进制校验问题。

4.1 任意进制字符串转十进制:逐位累乘与非法字符校验

把一个字符串按指定进制解析成数值,用的是「多项式累乘法」:从高位往低位,每读一位,把已有结果乘以进制再加上当前位的值。这个算法本质上就是霍纳法则,二进制转十进制时你会觉得眼熟——1011就是((1*2+0)*2+1)*2+1。

#include <stdio.h> #include <string.h> #include <ctype.h> int charToVal(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'Z') return c - 'A' + 10; if (c >= 'a' && c <= 'z') return c - 'a' + 10; return -1; } unsigned long long anyBaseToDec(const char *num, int base) { unsigned long long result = 0; int len = strlen(num); for (int i = 0; i < len; i++) { int val = charToVal(num[i]); if (val < 0 || val >= base) { return 0; // 非法字符,或该字符超出进制上限 } result = result * base + (unsigned long long)val; } return result; }

charToVal把字符映射成数值,同时支持大小写字母,这是「进制不分大小写」这个约定带来的便利。校验放在累乘的同一轮循环里,不需要先单独扫描一遍,省一趟遍历。base合法范围是2到36,超过36字符映射表就不够用了。调用方必须注意:返回值0可能表示合法输入"0",也可能表示非法输入,所以4.3节的主程序里会先strcmp判断,再决定是否报错。这属于接口设计的取舍——用返回0当错误码,省一个指针参数,代价是调用方多一行判断。

4.2 十进制转任意进制:查表编码与输出缓冲区的安全边界

void decToAnyBase(unsigned long long n, int base, char *out, size_t outSize) { const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char tmp[80]; int idx = 0; if (n == 0) { tmp[idx++] = '0'; } while (n > 0) { tmp[idx++] = digits[n % base]; n /= base; } if ((size_t)idx + 1 > outSize) { return; } int pos = 0; for (int i = idx - 1; i >= 0; i--) { out[pos++] = tmp[i]; } out[pos] = '\0'; }

这段和2.3的十六进制转换几乎一样,区别只在映射表从16个字符扩展到36个。所以「任意进制」本质上就是「给映射表加长」这么简单。tmp[80]对unsigned long long来说绝对够:64位整数转二进制也只要64个字符,加上结束符65字节,80留足了余量。输出缓冲区的outSize检查依然不能省,我把它看成数组操作的「安全带」。如果你把out指向一个栈上开好的char buf[16]却想塞进一个32位的十六进制结果,这个检查能拦住一次越界写。

4.3 组合运行:支持2到36进制互转的完整主程序

#include <stdio.h> #include <string.h> int main(void) { char input[100]; int fromBase, toBase; printf("输入数值: "); scanf("%99s", input); printf("输入源进制(2-36): "); scanf("%d", &fromBase); printf("输入目标进制(2-36): "); scanf("%d", &toBase); if (fromBase < 2 || fromBase > 36 || toBase < 2 || toBase > 36) { printf("进制必须在2到36之间\n"); return 1; } unsigned long long dec = anyBaseToDec(input, fromBase); if (dec == 0 && strcmp(input, "0") != 0) { printf("输入包含非法字符或超过进制范围\n"); return 1; } char result[80]; decToAnyBase(dec, toBase, result, sizeof(result)); printf("结果: %s\n", result); return 0; }

这段主程序把4.1和4.2串起来,也是我推荐的「最小完整工具」结构:输入→校验→转换→输出,四步各干各的。scanf("%99s", input)的99是故意留的防线,防止超长输入写爆数组,这是C语言基础里反复强调的scanf宽度限制。strcmp(input, "0")把「合法零」和「非法输入」分开,解决了4.1留下的歧义。你把它编译跑一遍,输入FF、源进制16、目标进制2,输出11111111。想拿去当课程设计交差,再加个while循环让用户连续转换,加个exit或quit指令就算完整题目了。

5. 数制转换避坑指南:逆序、溢出、字符映射的5个翻车现场

这一章全是踩坑记录,来源是我自己调试和帮人改代码的血泪经验。每条按「现象→原因→解决」写,你在实验或考试碰到同类问题,直接对号入座。

5.1 结果少一截还带乱码:数组容量不够的越界写

现象:十进制2147483647转二进制,输出的字符串明显比预期短,尾部还跟着一串乱码。原因:char result[32]只留了32字节。32位int二进制最多31位,加上结束符\0正好32字节,勉强够;一旦你处理的是long long,64位二进制需要65字节,数组直接越界写入相邻内存,把别人的数据踩了。解决:临时字符数组统一开成char tmp[80],并在逆序拷贝前检查idx + 1 <= outSize。宁可多开几十字节,也别省这块栈空间。

5.2 二进制转十进制出来负数:int装不下的整数溢出

现象:输入"1111111111111111111111111111111"(31个1)转十进制,得到负数或和手算不一致的值。原因:int范围是-2147483648到2147483647,31个1正好是2147483647,贴着边界;32个1直接溢出成-1,符号位被占用。解决:累乘累加的临时变量用unsigned long long,最多装64位整数的二进制表示。如果目标数本身超过64位,那就得手写大数除法,用数组模拟长除法,每一步记录商和余数——这是考研数据结构里的进阶题型,数制转换只是引子。

5.3 输出顺序永远是反的:忘了栈的后进先出

现象:25转二进制输出10011,手算是11001。原因:除基取余得到的余数序列低位在前,必须逆序才是高位在前。很多人把输出直接写在第一次余数产生的循环里,那等于先打印低位,顺序必反。解决:让入栈和出栈各占一个循环,中间别混写。判断标准很简单:第一个产生的余数是结果的最低位,一定最后打印。这个错误在多进制转换里同样出现,属于数制转换最经典也最冤的扣分点。

5.4 scanf吃换行导致第二轮输入为空:格式化匹配的坑

现象:程序支持连续转换,跑完第一轮,第二轮连输入提示都没正常走,或者scanf("%s")读到空串直接退出。原因:上一轮scanf("%d", &base)之后,输入缓冲区里残留一个\n;下一轮scanf("%s", input)不会跳过空白字符,一下子把空行当输入读了。解决:在字符串输入前加while (getchar() != '\n');清掉残留,或把格式串写成" %99s"(前面加个空格,scanf会跳过分隔符)。很多入门C语言题库和在线练习系统里,这类症状都指向同一个原因,排查顺序放在第一位。

5.5 LLONG_MIN取负溢出:64位边界的符号陷阱

现象:对-9223372036854775808做abs()或直接取负,结果还是负的,后续转换全部错乱。原因:LLONG_MIN的绝对值是9223372036854775808,超出long long正数上限,取负行为未定义。解决:先强转成unsigned long long再取负,写法是-(unsigned long long)n,借无符号类型的回绕语义拿到正确绝对值。这条和5.2本质一样,都是「有符号整数边界」在数制转换里的具体表现。我建议你在写转换函数时只对无符号整数做转换运算,符号单独挂在外层,能同时绕开这两个坑。

6. 进阶验证:用位运算重写转换函数并跑一个自测用例

二进制转换还有一种更贴近机器语义的写法:n % 2等价于n & 1,n / 2等价于n >> 1。位运算版本在不开优化时比除法版本快,开-O2后编译器会把除以常数2优化成移位,两者几乎持平。所以位运算的意义更多在于帮助你理解二进制在计算机里的真实形态,以及面试时应对「不用除法实现数制转换」这类题。

void decToBinBitwise(unsigned int n, char *out) { char tmp[33]; int idx = 0; if (n == 0) tmp[idx++] = '0'; while (n > 0) { tmp[idx++] = '0' + (n & 1); n >>= 1; } int pos = 0; for (int i = idx - 1; i >= 0; i--) { out[pos++] = tmp[i]; } out[pos] = '\0'; }

验证方法建议写一个对照测试:对0到100000之间的每个整数,分别用除法和位运算法生成二进制串,strcmp逐一比对,再用clock()统计总耗时。我自己常加一组自我校验数据,覆盖0、1、base-1、base、base*base、UINT_MAX这几个边界值;任意进制互转则做「往返测试」——decToAnyBase之后立刻anyBaseToDec,看结果是否还原。这套做法我沿用多年,比肉眼检查输出可靠得多,也是我这些年翻车明显变少的主要原因。希望帮到你。

本文还有配套的精品资源,点击获取

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

OpenShell完全指南:从安装配置到故障排查,找回Windows经典开始菜单

Windows 11 发布后&#xff0c;我身边几乎每周都有人抱怨那个新版开始菜单&#xff1a;磁贴没了、分组逻辑变了、搜索结果混着网页推荐&#xff0c;想快速打开一个控制面板得先想一下图标长什么样。我给人重装系统时最常做的事&#xff0c;就是在装完驱动之后顺手装一个叫 Open…

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

上下文模式(Context-Mode)设计:让大模型在复杂场景下稳定输出

做LLM应用开发&#xff0c;时间久了你会撞上一个特别拧巴的规律&#xff1a;同一个模型&#xff0c;换个场景、换个会话长度&#xff0c;回答质量就像过山车。很多时候问题并不在模型本身&#xff0c;而在context-mode——上下文模式。这个词是我在做客服机器人重构时自己冒出来…

作者头像 李华
网站建设 2026/10/6 4:06:57

GTK入门指南:从控件树到信号回调的图形界面开发实战

1. 先聊清楚&#xff1a;GTK是什么&#xff0c;值不值得学1.1 GTK在Linux生态里的位置最早接触GTK&#xff0c;还是因为想给一个简单的文本处理工具配上图形界面。那会儿我对Linux GUI开发的理解还停留在"Qt很重、用不起&#xff0c;Tkinter又太丑"的阶段。后来做调研…

作者头像 李华
网站建设 2026/10/6 4:05:46

Cursor Mac深度配置指南:解决权限、中文、Git与LSP四大痛点

简介&#xff1a;本资源是一份面向Mac平台Java开发者的Cursor编辑器安装与深度配置指南&#xff0c;解决中文用户在macOS环境下快速落地AI编程工具的核心痛点。压缩包共5个文件&#xff08;6KB&#xff09;&#xff0c;包含README说明文档&#xff08;.md&#xff09;、项目配置…

作者头像 李华
网站建设 2026/10/6 4:05:46

MySQL复习分水岭:DQL查询与表约束核心要点梳理

复习这两章之前&#xff0c;我一直有一种错觉&#xff1a;MySQL的增删改查已经会写了&#xff0c;第三第四章随便看看就行。真正开始二刷黑马程序员这套课才反应过来&#xff0c;第三章和第四章是整个MySQL基础的分水岭——前面你是在“能跑”&#xff0c;这两章才决定你能不能…

作者头像 李华
网站建设 2026/10/6 4:05:10

多智能体协作中的触达机制:从服务发现到语义路由的工程实践

我们团队最近在跑一套多智能体协作系统&#xff0c;最初大家各自调用API、各自维护上下文&#xff0c;结果数据到处都是&#xff0c;Agent之间互不相认&#xff0c;用户提一个跨模块的需求&#xff0c;系统要绕好几圈才能找到真正该干活的模块。后来我们把“让Agent之间能触达彼…

作者头像 李华