C语言变量、常量与指针深度解析:理解内存底层逻辑与编程实践
看到这个标题估计不少刚入门的朋友会觉得“这不就是基础语法嘛”也有工作几年的老哥们心里犯嘀咕变量、常量谁不会但指针这东西真的是C语言里绕不过去的坎也是面试时最喜欢深挖的点。我见过太多人能把声明背得滚瓜烂熟一让他写个链表或者回调函数就抓瞎。说到底这三个词不是孤立的语法点它们背后是一整套内存模型和程序运行逻辑。这篇文章我就从实际开发的角度把变量、常量、指针的关系掰开揉碎了讲清楚重点放在为什么会这样设计、实际写代码时怎么用、以及那些一不小心就踩进去的坑。先说清楚这三样东西解决的是同一个问题程序怎么在内存里存数据、读数据。变量是给一块可变内存起的名字常量是给一块只读数据或一个固定值定的规矩指针则是直接记录内存地址的变量。理解了三者在内存中的真实形态后面学数组、结构体、函数指针、动态内存分配都会顺滑很多。1. 变量、常量和指针的整体关系与设计思路很多教材把三者分开讲但实际开发中它们常常混在一起用。比如一个嵌入式项目的配置参数既要用常量防止误改又要用指针去遍历配置表。想搞清楚它们首先要建立内存视角。1.1 内存视角下的变量一块有名字的存储空间变量本质上是编译器和操作系统帮我们划好的一块内存区域这块区域有起始地址、有大小限制还有一个人类可读的名字。你在代码里写int count 0;编译器会在栈或者全局区分配4个字节具体看平台然后把符号表里count这个名字和这块内存的首地址关联起来。这里有个新手常犯的认知误区认为变量名就是内存地址。实际上变量名在编译后基本就消失了机器码里只有地址偏移。这也是为什么指针那么重要——它是唯一能在代码层面直接操作地址的手段。你可以这样理解内存是一栋公寓楼变量名是贴在房间门上的标签指针则是你手里写着门牌号的纸条拿着纸条你就能找到房间哪怕标签被撕了比如函数传参时形参名变了纸条依然有效。从实践经验来看写代码时要时刻问自己这个变量的作用域是什么生命周期有多长存储位置在栈、全局区还是堆上这三个问题决定了变量的行为也是后面排查莫名其妙的数据错乱问题时最先要检查的方向。1.2 常量写死的值如何编译和执行常量分两种字面常量和被const限定的变量。字面常量比如3、A、3.14、hello它们直接编码在指令里不占用额外的可读写内存。而const int MAX_SIZE 1024;本质上还是一个变量只是编译器禁止你通过常规赋值去修改它。为什么要引入const不只是为了“防止误改”更重要的是利用编译器做静态检查以及让代码意图更清晰。比如函数参数写成const char *str读你代码的人一眼就知道这个函数不会修改字符串内容也方便编译器做优化。我倾向于把const看作一种“只读契约”它保护的是编码规范而不是物理上的只读。有明显对比的是宏定义#define MAX_SIZE 1024。宏是在预处理阶段做的纯文本替换不占内存、没有类型而const变量有具体类型会进行类型检查。选型上现代C代码里能用const的地方就少用宏但如果需要控制编译条件、生成枚举列表、嵌入字符串化场景宏依然是不可替代的。1.3 指针C语言的灵魂也是最大的难点指针就是一个值为内存地址的变量。它用几个字节的空间64位平台是8字节存储另一个变量的地址通过解引用操作*p来访问目标变量。这个机制带来了三个核心能力间接寻址函数可以通过指针修改调用者的局部变量解决C语言只能值传递的问题。动态内存malloc返回的就是void *没有指针就无法在堆上创建运行时才能确定大小的数据结构。类型抽象函数指针让回调机制成为可能void *则可以写出通用数据结构。但指针也是大量段错误和内存泄漏的源头。据我观察90%的指针问题都集中在三类未初始化指针、悬空指针、越界访问。后面我会专门展开说。2. 核心细节解析与实操要点这部分我挑在开发和面试中出现频率最高的几个知识点配上实操中的注意事项确保你能直接用上。2.1 变量的作用域、链接属性与生命周期写代码时要结合存储类别去理解变量。这里有张表能快速帮你理清思路写法作用域生命周期存储位置建议用途函数内普通局部变量函数内函数调用期间栈临时计算static局部变量函数内程序运行期间静态区计数器、单例状态全局变量整个文件程序运行期间静态区共享状态慎用static全局变量仅当前文件程序运行期间静态区模块内部共享extern声明变量跨文件程序运行期间静态区多文件协作注意区分static的两种含义修饰局部变量时改变生命周期修饰全局变量时改变链接属性。很多面试题喜欢在这里挖坑让你推测某个static变量的输出其实考的就是你是否清楚变量在内存中的存放位置和初始化时机。实操中的一条硬性建议局部变量务必初始化。栈上的未初始化变量是随机值gcc在-O0下往往不给你清零一旦后续逻辑没覆盖到所有路径就会拿到野值。尤其是结构体变量直接用 {0}或者memset清零养成习惯能省掉大量排查时间。2.2 常量使用细节const的三种常见形态const的难点在于它和指针组合的声明解析。记住一条规则const修饰的是它右边紧挨着的东西如果右侧已经是*则修饰指针指向的类型。举个例子来对照理解const int *p1; // p1 本身可变但 *p1 不能通过 p1 修改 int const *p2; // 与 p1 完全等价 int *const p3; // p3 本身不可变但 *p3 可以修改 const int *const p4; // 两者都不可变我的记忆方法是先看const右边有没有*。右边是*的话说明它修饰的是“指针指向的目标”为只读右边是变量名的话说明它修饰“指针本身”为只读。实际编码中const int *最常用于函数形参表示只读入参int *const常用于数组名场景的固化和嵌入式寄存器地址映射。再补充一个很多人会忽略的点const变量不是编译期常量。它不能用于数组长度声明在标准C中变长数组VLA另说也不能用于case标签。如果你真的需要编译期常量请用enum或#define。这个区别是实用性很强的知识点。2.3 指针运算与数组的关系指针移动的真相指针加减整数移动步长不是1个字节而是sizeof(类型)个字节。这个设计是为了让p n能直接定位到数组第n个元素。也就是说*(p 3)和p[3]完全等价数组名字在表达式里会被隐式转换为首元素地址。这里有很多人容易混淆的一个点数组名到底是常量指针还是指针常量严格说数组名不是指针变量它是一个值无法被直接赋值。但它在大多数字表达式里会“退化”成指向首元素的指针。唯一的例外是sizeof(arr)和arr前者得到整个数组长度后者得到指向整个数组的指针类型是int (*)[N]。实操场景里我常看到这样的代码问题void fill_array(int arr[], int len) { // arr 其实已经是退化成指针了, sizeof(arr) 不对 } int main(void) { int data[10]; fill_array(data, 10); return 0; }在fill_array内部对arr使用sizeof(arr)得到的是指针大小不是数组大小除非传入数组长度否则你无法知道数组边界。这就是为什么C函数传数组一定同时传长度的原因。2.4 二级指针、指针数组与函数指针进阶必备二级指针int **pp里存的是一个int *变量的地址。它的典型场景是“需要修改指针本身”时比如链表插入、释放后置空。最常见的错误写法是void free_ptr(int *p) { free(p); p NULL; // 只改了形参拷贝, 外部指针还是悬空 }正确做法是传指针的指针void free_ptr(int **p) { free(*p); *p NULL; }。这个细节在写大型项目时很关键因为悬空指针二次释放会直接崩溃或引发未定义行为。指针数组和数组指针也要分清。char *strArr[10]是指针数组里面存了10个char *常用于字符串表int (*ptr)[10]是数组指针指向一个包含10个int的数组常用于二维数组行操作。函数指针则声明为int (*handler)(int, int)用起来像变量一样灵活是回调机制的基础。每次写这些声明时我习惯用工具反查或者自己用“右左法则”过一遍避免声明和实际用途错位。3. 实操过程与核心环节实现说一千道一万不如亲手写一遍。这一节我从零到一实现一个小工具读取一组学生成绩统计平均分、最高分和及格率过程中尽可能用到变量、常量、指针的关键操作。先搭框架再填细节。3.1 场景设计与约束梳理这个工具的需求很简单从标准输入读入若干个成绩0-100分输出平均值、最高分和及格人数。我刻意把功能限制得很窄这样才能把注意力放在语言本身。为了体现const的用途我会把成绩数组按只读方式传给统计函数为了体现指针操作我会用指针遍历数组而不是用下标为了体现动态内存我会根据输入人数malloc一个堆数组而不是固定长度。模块划分入口读入人数和成绩分配内存。统计模块求平均、最高分、及格率全部基于const int *操作。清理模块释放内存并置空指针。选这样的方案是考虑到新手能一次性看到栈区、全局区、堆区三种变量以及输入参数和返回结果的指针使用模式。3.2 完整实现带讲解的可编译代码下面给出完整代码在gcc -stdc11下编译测试过#include stdio.h #include stdlib.h #define PASS_LINE 60 // 及格线常量 /** * 统计一组成绩的平均分 * param scores 只读成绩数组 * param count 成绩个数 * return 平均分 */ static double calc_average(const int *scores, int count) { if (scores NULL || count 0) { return 0.0; } int sum 0; const int *p scores; const int *end scores count; // 指针越界保护: end指向末尾后一位 while (p end) { sum *p; p; } return (double)sum / count; } /** * 统计最高分 * param scores 只读成绩数组 * param count 成绩个数 * return 最高分, 无有效数据时返回 -1 */ static int calc_max(const int *scores, int count) { if (scores NULL || count 0) { return -1; } int max scores[0]; for (int i 1; i count; i) { if (scores[i] max) { max scores[i]; } } return max; } /** * 统计及格人数 * param scores 只读成绩数组 * param count 成绩个数 * return 及格人数 */ static int count_pass(const int *scores, int count) { if (scores NULL || count 0) { return 0; } int passed 0; const int *p scores; for (int i 0; i count; i) { if (*(p i) PASS_LINE) { passed; } } return passed; } int main(void) { int n 0; printf(请输入学生人数: ); if (scanf(%d, n) ! 1 || n 0) { fprintf(stderr, 输入人数无效\n); return 1; } // 堆区分配, 只有 n 在运行时确定, 所以必须用动态内存 int *scores (int *)malloc(sizeof(int) * n); if (scores NULL) { fprintf(stderr, 内存分配失败\n); return 1; } for (int i 0; i n; i) { printf(请输入第%d个成绩: , i 1); scanf(%d, scores[i]); } double avg calc_average(scores, n); int max calc_max(scores, n); int passed count_pass(scores, n); printf(平均分: %.2f\n, avg); printf(最高分: %d\n, max); printf(及格人数: %d\n, passed); // 用临时二级指针演示函数无法直接修改指针本身的经典场景 int *tmp scores; scores NULL; free(tmp); return 0; }3.3 代码关键点与参数分析先说calc_average里的指针操作。我定义了end scores count然后while (p end)遍历。这里强调一下end指向数组末尾的下一个位置这个元素不存在但C标准允许创建这样的“尾后指针”只要不解引用它就行。这就是典型的使用指针而非下标进行遍历比for (i0;icount;i)的做法更能体现指针特征。为什么scores参数要加const原因有两点一是明确告诉调用方这个函数不会改成绩数组二是如果内部不小心写了scores[0] 100编译器直接报警把错误挡在编译阶段。这是用编译器的力量减少运行时bug成本几乎为零收益很高。注意malloc的结果强制转成int *的写法。C语言中void *可以隐式转换为任意类型指针不写转换也能编译。但从C兼容性和可读性角度显式转换更稳妥。同时malloc的返回值一定要检查否则在内存紧张时后续解引用会直接崩掉。释放内存时我用了一个临时变量tmp来保存原始地址再把scores置空。有人会问为什么不直接free(scores)然后scores NULL原因在于我想演示传值语义的坑——如果这个清理动作发生在子函数里就必须用二级指针。这里放一个更常见的清理函数写法static void clear_scores(int **scores_ptr) { if (scores_ptr NULL) return; free(*scores_ptr); *scores_ptr NULL; }调用时clear_scores(scores)。这样外部scores才真正变成NULL避免悬空指针被再次使用。这种写法在真实项目里几乎是标配尤其是封装释放接口时。3.4 测试结果与边界验证我实际编译运行了几组数据其中一组输入5个成绩88 72 45 93 60。程序输出平均分: 71.60 最高分: 93 及格人数: 3边界情况我也做了验证输入0人时程序直接提示“输入人数无效”并退出只输入1人时count_pass还能正确判断calc_max不会越界。这些边界保护不是可选项而是必须项因为C没有自动越界检查很多漏洞就是从这些“没人会输入”的极端值开始的。顺手测试了malloc失败分支通过不断申请大内存可以触发NULL返回代码没有崩溃而是打印错误信息退出。这个分支平时测试覆盖不到但线上偶发内存紧张时就是救命的稻草。4. 常见问题与排查技巧实录这部分我直接整理成实战速查每个问题都是我看到过很多次的真实翻车场景建议收藏备用。4.1 典型指针错误与避坑方法先看几个高频问题的对照表问题现象典型原因解决方案程序崩溃Segmentation fault解引用NULL指针或野指针指针初始化、检查malloc返回值、用NULL替代未定值函数内赋值外部变量不变值传递只改了拷贝传指针或指针的指针free后再次访问或再次free悬空指针、二次释放free后立即置NULL修改了不该改的数据通过非const指针绕过const传参时保持const一致性必要时用强制转换需非常谨慎数组越界没有立刻报错越界写破坏相邻内存严格计算边界、使用n-1上限校验、AddressSanitizer辅助排查不同平台计算结果不一致整型溢出、大小端差异使用固定宽度整数类型stdint.h、显示转换排查段错误时我习惯先用调试器直接定位。gdb下运行后输入bt能拿到调用栈再print p看指针值立刻就能知道是不是0x0或者垃圾地址。如果没有调试器环境在可疑代码前后打印__LINE__和关键指针值二分定位也行。我在实际工作中发现很多人犯错是因为省掉了初始化比如声明指针后没有赋值就解引用这在栈区大概率落到一个随机值解引用直接崩。4.2 编译警告与静态分析工具的使用gcc开了-Wall -Wextra之后能发现大量野指针和类型错误。但-Wall并不是真“所有警告”我还会习惯性加-Wshadow检查变量遮蔽、-Wconversion检查隐式整型转换。养成“编译零警告”的习惯比你以为的更重要很多运行时问题在编译阶段已经有苗头了。再用valgrind做内存泄漏检测。命令很直接valgrind --leak-checkfull ./program看到definitely lost就要回头查malloc和free配对情况。这个工具对于排查指针相关的“神秘问题”几乎是必杀技。现代IDE和在线编译器更省事但命令行工具的场景适应面更广。4.3 从一段错误代码学会排查思路我模拟一个经典面试错误的排查过程。假设有下面这段代码#include stdio.h char *get_message(void) { char msg[] hello world; return msg; // 栈内存, 函数返回后就失效了 } int main(void) { char *p get_message(); printf(%s\n, p); return 0; }编译时加-Wall会给出function returns address of local variable警告。即便不编译你也应该形成条件反射局部数组在栈上函数结束栈帧销毁返回的地址就“悬空”了。想修复有两种思路一是返回字符串常量静态区二是调用方传入目标缓冲区。第一种省事但不适合动态内容第二种更通用。这也是为什么大量C接口都设计成char *dst, const char *src的形式。排查这类问题的心得是先确认指针指向的“内存归属权”。栈、堆、静态区、代码段每一类都有不同的生命周期规则。内存在哪里生命周期有多长是谁分配谁释放这就是C指针调试的核心要点。你把这三个问题想清楚了等于把大部分指针问题都消灭在编码阶段。5. 从项目实践谈学习路径我对初学者的建议是不要孤立地背语法而是在小项目里反复运用。先做别人设计好的模块如上面这个成绩统计再把每个函数改造成指针版本甚至把数组换成动态内存感受形态变化然后尝试自己设计一个环形缓冲区或者链表这能强迫你把变量生命周期和指针归属搞得清清楚楚。我觉得学C最关键的阶段不是学会语法而是建立起“内存操作”的直觉。踩过几次坑之后我反而养成了几个好习惯所有函数参数能写const就写const每次malloc都立即写对应的清理逻辑释放指针后立刻置空条件分支里出现指针时多问一句“它会不会是NULL”。这些习惯在C项目里不算高深但确实能大幅减少夜间被手机震醒的概率。最后再分享一个小技巧当你被一个诡异的指针问题折磨时别光盯着代码看试着画一张内存布局图。把每个变量的地址、值、指向关系标出来问题往往一眼就暴露了。我至今还保留着在纸上画格子标注地址和大小的习惯这个延续自调试器的思维方式比单纯多看两小时代码高效得多。

相关新闻

js-filesearch:一个纯Node.js命令行文件搜索与内容检索工具

js-filesearch:一个纯Node.js命令行文件搜索与内容检索工具

简介:这是一份基于Node.js(JavaScript)的文件夹文件搜索工具项目,主要面向需要快速定位文件的开发者,也适合初学者借助源码学习Node.js文件操作与异步编程。项目采用模块化结构,包含搜索、用户界面、文件系…

2026/10/12 13:54:04 阅读更多 →
智能体友好API设计:从契约、幂等到可观测性的工程实践

智能体友好API设计:从契约、幂等到可观测性的工程实践

1. 从"能跑通"到"扛得住":智能体调用API的真实痛点做过AI应用的朋友大概率都经历过这个阶段:本地写个Demo,调一调大模型接口,跑通一个对话或者一个自动化流程,感觉一切都很美好。可一旦要把这套东…

2026/10/12 13:53:03 阅读更多 →
华为云AgentArts实战:金融信贷AI智能体搭建与提示词工程

华为云AgentArts实战:金融信贷AI智能体搭建与提示词工程

1. 从信贷审批的痛点说起:为什么要在云上搭一个AI智能体做过金融信贷系统的人都有一个共同感受:这个领域的业务逻辑复杂到让人头皮发麻。一笔贷款从进件到放款,中间要过反欺诈、征信查询、收入核实、负债计算、额度定价、风险分级、合规审查等…

2026/10/12 13:53:03 阅读更多 →

最新新闻

二叉树进阶攻略:递归、迭代、层序与经典题型全解析

二叉树进阶攻略:递归、迭代、层序与经典题型全解析

算法训练营第十四天:二叉树(2) 到了第十三天,我们基本上把二叉树的"骨架"摸清了:节点结构、树的定义、递归遍历的套路。那十四天干嘛?两个字:深化。二叉树(2)…

2026/10/12 14:48:18 阅读更多 →
卫星通信入网三关:物理连通、协议接入与业务可用性验证

卫星通信入网三关:物理连通、协议接入与业务可用性验证

简介:本资源是一份面向通信工程专业学生、卫星地面站建设工程师及网络测试技术人员的实务型教学课件,系统讲解卫星通信网络从建站、入网验证到系统测试的全流程规范与关键技术。内容覆盖新地球站入网申请审批(国内经原邮电部电信总局、国际由…

2026/10/12 14:48:18 阅读更多 →
Agent记忆系统实战:上下文窗口限制与MCP统一工具记忆

Agent记忆系统实战:上下文窗口限制与MCP统一工具记忆

1. 先理解Agent为什么“记不住”:上下文窗口的边界与失真1.1 上下文窗口是工作台,不是仓库我最早做Agent原型时犯过一个很天真的错误:以为模型能记住对话里出现过的所有信息。后来被现实狠狠教育了一课——上下文窗口更像一张有限大小的办公桌…

2026/10/12 14:48:18 阅读更多 →
Keras复现YOLOv1:从零训练自己的数据集实战指南

Keras复现YOLOv1:从零训练自己的数据集实战指南

简介:这份资源面向希望上手目标检测的深度学习研究者与开发者,围绕Keras版YOLOv1算法,提供训练自有数据集的完整配套材料。YOLOv1将检测视为回归问题,速度优势明显,而Keras高层API降低了实现门槛,二者结合便…

2026/10/12 14:48:18 阅读更多 →
MATLAB读取RINEX观测文件:从解析到定位解算的完整指南

MATLAB读取RINEX观测文件:从解析到定位解算的完整指南

简介:这份资源面向从事GNSS数据处理、测绘与导航定位方向的科研人员和工程技术人员,提供了一套用MATLAB读取RINEX格式GPS观测文件的程序,并附带测试数据用于验证解析结果。RINEX作为接收机独立交换格式,广泛用于GPS、GLONASS、Gal…

2026/10/12 14:48:18 阅读更多 →
WorkBuddy低代码工作流实战:从单点任务到业务闭环

WorkBuddy低代码工作流实战:从单点任务到业务闭环

1. 这不是一场普通征稿:WorkBuddy 应用指南征集背后的“真实战场”你点开这个标题,第一反应可能是——又一个企业发的软广?领积分、换周边?听起来像行政部发的季度团建通知。但如果你真这么想,就错过了一个正在 quietl…

2026/10/12 14:47:16 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器: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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →