C语言scanf连续输入问题:缓冲区机制与实战解决方案
1. 项目概述为什么“连续输入”是C语言新手的第一个拦路虎刚学C语言那会儿你是不是也遇到过这种情况写了个程序本意是让用户输入两个数字然后计算它们的和。你信心满满地输入了“10 20”然后按下了回车。结果呢程序要么直接跳过了第二个输入要么卡在那里要么输出一堆莫名其妙的数字。你盯着屏幕上的scanf(“%d%d”, a, b);这行代码百思不得其解——语法没错啊书上也这么写的怎么到我这儿就不灵了这就是典型的“连续输入”问题它几乎是每个C语言初学者在接触用户交互时遇到的第一个、也是最让人困惑的实战难题。它不像语法错误那样会被编译器直接标红而是表现为一种逻辑上的“别扭”和“不听话”让程序的行为和你的预期南辕北辙。这个问题的核心远不止是学会用while循环套scanf那么简单。它涉及到C语言标准输入输出I/O缓冲区最底层的工作机制、格式化输入函数scanf的“贪婪”与“挑剔”、以及程序如何感知“输入结束”这个信号。网上很多教程只给代码片段比如经典的while(scanf(“%d”, n) ! EOF)但很少告诉你为什么必须这么写scanf的返回值到底代表什么缓冲区里残留的换行符\n是怎么捣乱的以及在处理混合类型输入比如整数后紧跟字符串时会埋下多大的坑。如果你只是机械地背下几个“模式”而不理解背后的原理那么只要题目稍加变化比如从输入数字变成输入字符或者要求以特定字符结束你立刻又会束手无策。本文将彻底拆解C语言中的连续输入问题。我会从一个从业多年的角度带你回到输入输出的“现场”看看键盘敲下的字符是如何一步步被程序接收和处理的。我们会深入scanf函数的内部逻辑理解它的返回值、格式匹配规则和缓冲区交互方式。然后我会给出针对不同场景纯数字、混合类型、文件重定向、循环结束判断的、可直接“抄作业”的解决方案模板并附上每一步的详细解释和避坑指南。无论你是正在被翁恺老师课后题困扰的学生还是在做“网吧计费管理”之类小项目时遇到输入瓶颈的开发者这篇文章都能帮你把“输入”这块基石打牢。2. 核心原理深度解析scanf与输入缓冲区的“爱恨情仇”要解决连续输入问题绝对不能把scanf当成一个黑盒子。你必须明白程序并非直接从键盘读取数据而是从一个叫做“标准输入缓冲区”的中间区域读取。你的每一次按键包括数字、字母、空格、回车都会先进入这个缓冲区排队。scanf函数的工作就是根据你提供的格式字符串如%d,%s从这个缓冲区里“提取”并转换数据。2.1 scanf的“提取”逻辑与返回值密码scanf的行为可以概括为“按格式索取遇阻则停”。当我们调用scanf(“%d”, num)时它做了以下几件事跳过前导空白字符包括空格 、制表符\t和换行符\n。这是很多人忽略的关键点%d在开始匹配数字前会自动清除缓冲区开头这些“噪音”。尝试匹配转换试图从当前缓冲区位置开始按照整数格式解析字符。如果遇到的第一个非空白字符是数字则继续读取直到遇到非数字字符然后将读取到的数字字符串转换为整数存入num。停止与残留转换成功后scanf会停在那个“终止字符”前。这个终止字符比如你输入123abc后按回车那么终止字符就是a仍然留在输入缓冲区里等待下一次读取。返回成功赋值项数这是scanf最关键的返回值。它返回的是成功匹配并赋值了的输入项的个数。如果期待一个整数%d但用户输入了字母则匹配失败返回0。如果遇到文件结束符EOF则返回EOF通常定义为-1。注意scanf(“%d”, num)在用户直接按下回车缓冲区只有一个\n时会因\n是空白字符而被跳过但跳过不代表成功读取。此时程序会继续等待直到有非空白字符输入。这解释了为什么有时程序会“卡住”不动。2.2 缓冲区残留万恶之源的“\n”最常见的坑就来自缓冲区里残留的换行符\n。考虑以下代码int age; char name[20]; printf(“Enter your age: “); scanf(“%d”, age); // 用户输入25然后回车 printf(“Enter your name: “); scanf(“%s”, name); // 问题出现过程分析第一次scanf(“%d”, age)读取数字25遇到回车键产生的\n停止\n留在缓冲区。第二次scanf(“%s”, name)%s也会跳过前导空白字符于是它跳过了那个残留的\n。但是%s以空白字符空格、制表符、换行作为字符串结束的标志。由于\n已经被跳过而缓冲区又空了程序便等待用户输入。用户输入John并回车后scanf读取John遇到新的\n停止这个新的\n又留在了缓冲区。 看起来好像这次没问题但想象一下如果第二个scanf是%c读取单个字符情况就完全不同了。%c是唯一一个不跳过任何前导空白字符的格式说明符。它会直接读取缓冲区里残留的那个\n导致你根本没机会输入新字符name就被赋值为换行符了。2.3 EOF不仅仅是文件的结束在交互式终端中如何告诉程序“我输完了”这需要用到EOFEnd Of File。在Windows命令行中通常按CtrlZ然后回车在Linux/Mac终端中按CtrlD。这个操作并不会向缓冲区输入一个字符而是设置一个流状态标志让scanf等读取函数感知到“流已结束”。当scanf在尝试读取时遇到EOF它会立即返回EOF。这正是while(scanf(…) ! EOF)这种循环控制模式的理论基础——它让程序能够处理未知数量的输入行直到用户主动发送结束信号。3. 实战场景与解决方案模板理解了原理我们来看具体场景。我将问题分为四类并为每一类提供经过验证的代码模板和解释。3.1 场景一未知数量的纯数字输入如求总和、平均值这是最简单的场景目标是一直读取整数直到遇到EOF或非法输入。经典模板翁恺练习题常见#include stdio.h int main() { int num; int sum 0; // 关键循环scanf成功读取一个整数就进入循环体 while (scanf(“%d”, num) 1) { sum num; } printf(“Sum %d\n”, sum); return 0; }操作与解释如何运行在终端一行输入多个数字用空格隔开或者每行输入一个数字都可以。结束时输入EOF信号CtrlD或CtrlZ。为什么是 1scanf(“%d”, num)成功读取一个整数时返回1。只要返回1说明输入有效循环继续。当遇到非数字字符如字母或EOF时scanf返回0或EOF循环条件为假退出。缓冲区清理这个模板对于纯数字输入非常干净因为%d会自动跳过数字之间的空白符包括换行所以输入格式很自由。3.2 场景二先数字后字符串或字符的混合输入这是新手踩坑的重灾区核心矛盾就是上文提到的残留\n。安全模板处理%d后接%s#include stdio.h int main() { int id; char name[50]; printf(“Enter ID: “); scanf(“%d”, id); // 读取整数回车符\n留在缓冲区 // **关键清理步骤**使用“%*c”或getchar()消耗掉残留的换行符 scanf(“%*c”); // ‘%*c’表示读取一个字符并丢弃不赋值给任何变量 // 或者用 getchar(); 效果类似 printf(“Enter Name: “); scanf(“%s”, name); // 现在可以安全读取字符串了 printf(“ID: %d, Name: %s\n”, id, name); return 0; }安全模板处理%d后接%c#include stdio.h int main() { int age; char initial; printf(“Enter age: “); scanf(“%d”, age); // **对于%c清理要求更严格**在%c前加一个空格 printf(“Enter initial (one letter): “); scanf(” %c”, initial); // 注意%c前面的空格 printf(“Age: %d, Initial: %c\n”, age, initial); return 0; }要点解析scanf(“%*c”)*是赋值抑制符意思是“读取这个数据但扔掉它不保存”。这里用它精确地消耗掉缓冲区里那个讨厌的\n。scanf(” %c”, …)%c前的空格至关重要。这个空格会指示scanf跳过任意数量的空白字符包括之前残留的\n直到遇到第一个非空白字符才开始读取。这是处理%c前有空白符残留的标准做法。为什么不总是用getchar()getchar()在简单场景下有效但如果缓冲区里不止一个字符比如用户误输入了空格加回车单个getchar()可能清不干净。而” %c”或循环清理直到\n是更健壮的做法。3.3 场景三基于特定终止符的循环输入如输入0停止有时题目要求输入一系列数以0作为结束标志。健壮模板#include stdio.h int main() { int value; printf(“Enter numbers (0 to stop):\n”); // 使用while(1)无限循环在内部进行判断和break while (1) { if (scanf(“%d”, value) ! 1) { // 输入的不是数字清理缓冲区并提示错误 printf(“Invalid input! Please enter an integer.\n”); while (getchar() ! ‘\n’); // 清空当前错误行所有残留字符 continue; // 跳过本次循环重新尝试输入 } if (value 0) { break; // 遇到终止条件退出循环 } // 处理有效的value printf(“You entered: %d\n”, value); } printf(“Input finished.\n”); return 0; }设计思路先检查输入有效性scanf返回值不等于1说明匹配%d失败用户输入了字母等。这是处理非法输入的关键。彻底清理无效输入while (getchar() ! ‘\n’);这行代码是一个经典技巧。它会循环读取并丢弃缓冲区中的每一个字符直到遇到换行符\n为止。这确保了无论用户在这一行误输入了多少乱七八糟的内容都会被清空不会影响下一次scanf的读取。后判断终止条件在确认输入是有效数字后再判断它是否为0。逻辑清晰避免将非法输入误判为终止信号。3.4 场景四整行读取与解析更高级的灵活性当输入格式复杂比如一行中包含用逗号分隔的多个不同类型数据时直接用scanf会很痛苦。这时更优的策略是先用fgets读取整行字符串到缓冲区再用sscanf或字符串处理函数如strtok进行解析。模板示例读取“姓名,年龄,分数”格式的行#include stdio.h #include string.h int main() { char line[100]; char name[50]; int age; float score; printf(“Enter ‘Name,Age,Score’: “); // fgets读取整行包括换行符 if (fgets(line, sizeof(line), stdin) NULL) { printf(“Error or EOF encountered.\n”); return 1; } // 去掉末尾可能存在的换行符 line[strcspn(line, “\n”)] ‘\0’; // 使用sscanf从字符串line中解析数据 if (sscanf(line, “%[^,],%d,%f”, name, age, score) 3) { printf(“Name: %s, Age: %d, Score: %.2f\n”, name, age, score); } else { printf(“Invalid format!\n”); } return 0; }优势分析安全fgets指定了缓冲区大小避免缓冲区溢出scanf(“%s”, name)不做长度检查是危险的。清晰输入和解析分离。你可以先看到完整的输入行调试更方便。强大sscanf的格式字符串非常灵活。%[^,]表示读取一个字符串直到遇到逗号,为止这完美匹配了我们的需求。可控如果一行解析失败不影响下一行的读取错误处理更简单。4. 常见疑难杂症与深度避坑指南即使掌握了模板在实际编码尤其是在完成一些特定题目如“网吧计费管理”需要记录时间、“最优二叉搜索树”需要读取大量数据时你仍会碰到一些诡异的问题。下面是我从大量调试经验中总结出的“避坑清单”。4.1 陷阱一scanf(“%s”)的缓冲区溢出漏洞char str[10]; scanf(“%s”, str);这是极其危险的。如果用户输入超过9个字符留一个给结尾的\0程序就会写入不属于它的内存导致未定义行为崩溃、数据损坏是最轻的。绝对不要在生产代码中这样使用。安全做法使用带宽度限制的scanfscanf(“%9s”, str);确保最多读取9个字符。首选fgetsfgets(str, sizeof(str), stdin);这是读取字符串最安全、最标准的方式。注意fgets会保留换行符可能需要手动去除。4.2 陷阱二在循环中使用scanf(“%c”)读取菜单选项这是一个经典死循环场景char choice; do { printf(“Menu: (A)dd (D)elete (Q)uit\n”); scanf(“%c”, choice); // 问题代码 // … 处理 choice … } while (choice ! ‘Q’);你会发现程序经常莫名其妙地打印两次菜单。原因就是每次你输入选项如A后按的回车\n被下一次循环的scanf(“%c”)直接读走了而\n不是有效选项所以又打印菜单。根治方案永远使用scanf(” %c”, choice);%c前加空格让scanf帮你跳过所有空白字符直接读取你按的字母键。4.3 陷阱三处理输入错误后的状态恢复如果scanf期待数字却收到了字母不仅这次读取失败这个“字母”还会一直留在缓冲区导致后续所有的scanf都失败陷入无限循环。解决方案就是前面提到的“清空缓冲区”技术int num; while (printf(“Enter a number: “), scanf(“%d”, num) ! 1) { printf(“That’s not a valid number!\n”); // 清空缓冲区中错误的输入直到换行符 while (getchar() ! ‘\n’); } printf(“You entered: %d\n”, num);这里的while (getchar() ! ‘\n’);是救命的代码。逗号运算符,让我们可以在循环条件中先执行提示再判断输入结果。4.4 陷阱四文件重定向输入时的细微差别当你用./myprogram input.txt运行程序时输入来自文件而不是键盘。这时EOF行为是明确的文件结束即EOF但缓冲区行为不变。所有针对交互式输入的技术如清空缓冲区依然有效。需要特别注意的是文件末尾可能没有换行符这可能会影响一些依赖\n来判断行结束的代码逻辑。更健壮的做法是使用fgets进行行读取它可以明确地告诉你是否读取到了一整行。5. 从理论到实践构建一个健壮的学生成绩输入模块让我们综合运用以上所有知识完成一个稍复杂点的任务编写一个程序循环读取多个学生的信息每行格式为“姓名 年龄 C语言成绩”直到用户输入EOF。需要能处理错误的输入行并计算平均成绩。#include stdio.h #include string.h #include ctype.h // 用于isspace #define MAX_NAME_LEN 50 #define MAX_LINE_LEN 100 int main() { char line[MAX_LINE_LEN]; char name[MAX_NAME_LEN]; int age; float score, total_score 0.0f; int student_count 0; printf(“Enter student records (Name Age Score). Press CtrlD to end.\n”); printf(“Example: ZhangSan 18 95.5\n”); // 使用fgets进行整行读取这是处理交互式和文件输入最稳健的方式 while (fgets(line, sizeof(line), stdin) ! NULL) { // 1. 预处理去除行尾换行符 line[strcspn(line, “\n”)] ‘\0’; // 2. 安全检查跳过空行或纯空白行 int is_blank 1; for (int i 0; line[i] ! ‘\0’; i) { if (!isspace((unsigned char)line[i])) { is_blank 0; break; } } if (is_blank) { continue; // 跳过空白行继续读取下一行 } // 3. 使用sscanf解析并检查返回值确保三项都匹配成功 // 注意%s读取字符串遇到空白格停止所以名字不能有空格 if (sscanf(line, “%49s %d %f”, name, age, score) 3) { // 4. 简单的数据有效性验证可根据需求扩展 if (age 0 || age 150) { fprintf(stderr, “Error: Invalid age (%d) for student %s. Record ignored.\n”, age, name); continue; } if (score 0.0f || score 100.0f) { fprintf(stderr, “Error: Invalid score (%.2f) for student %s. Record ignored.\n”, score, name); continue; } // 5. 处理有效数据 total_score score; student_count; printf(“Added: %s, %d years old, score: %.2f\n”, name, age, score); } else { // 6. 处理格式错误的行 fprintf(stderr, “Error: Invalid format in line: ‘%s’. Expected ‘Name Age Score’.\n”, line); // 可以选择不清除缓冲区因为fgets已经读取了整行下次循环会读取新行 } } // 7. 输出统计结果 if (student_count 0) { printf(“\n Summary \n”); printf(“Total students: %d\n”, student_count); printf(“Average score: %.2f\n”, total_score / student_count); } else { printf(“No valid student records entered.\n”); } return 0; }这个案例的精髓在于输入与解析分离用fgets扛下所有输入保证程序不会因奇怪的输入而崩溃。健壮的解析用sscanf返回值严格检查格式匹配成功项数。数据清洗与验证去除换行符、跳过空白行、对年龄和成绩进行合理性校验。清晰的错误处理使用fprintf(stderr, …)将错误信息输出到标准错误流与正常输出分离符合Unix编程哲学。用户友好提示输入格式并回显成功添加的记录。掌握了这套组合拳你就能应对C语言中绝大多数输入需求无论是简单的OJ题目还是带有一定复杂性的课程设计项目。记住处理输入的核心思想永远是明确边界、清理残留、验证数据、优雅处理异常。把这四点做到位你的程序就离“健壮”不远了。

相关新闻

腾讯WorkBuddy AI助手深度体验:中文办公场景的智能效率革命

腾讯WorkBuddy AI助手深度体验:中文办公场景的智能效率革命

1. 项目概述:为什么是WorkBuddy?最近在AI工具圈里,腾讯悄悄上线了一款名为“WorkBuddy”的AI助手,身边不少朋友和同事都在问,市面上那么多AI助手,从ChatGPT到Claude,从Kimi到DeepSeek&#xff0…

2026/10/12 22:23:24 阅读更多 →
C++实现康威生命游戏模拟器:从高斯帕滑翔机枪到细胞分裂

C++实现康威生命游戏模拟器:从高斯帕滑翔机枪到细胞分裂

1. 项目缘起:从“生命游戏”到“高斯帕滑翔机枪”几年前,我在一个图形学相关的项目中,为了测试一个简单的像素渲染引擎的性能,随手写了一个康威生命游戏的模拟器作为“测试用例”。生命游戏(Game of Life)这…

2026/10/13 2:08:46 阅读更多 →
OneNav书签管理主题切换完整教程:3分钟从默认换到自定义主题

OneNav书签管理主题切换完整教程:3分钟从默认换到自定义主题

OneNav书签管理主题切换完整教程:3分钟从默认换到自定义主题 【免费下载链接】onenav 使用PHP SQLite 3开发的书签管理系统,将浏览器书签集中式管理,做到一处部署,随处访问。 项目地址: https://gitcode.com/gh_mirrors/on/one…

2026/10/5 13:04:43 阅读更多 →

最新新闻

关系模型实战指南:从二维表到业务稳定性的底层逻辑

关系模型实战指南:从二维表到业务稳定性的底层逻辑

1. 这不是教科书里的“关系”,而是你每天都在用的数据组织逻辑“关系模型的基本概念”——看到这八个字,很多人第一反应是大学数据库课上那个被粉笔灰笼罩的下午,黑板上写着“实体、属性、域、键”,讲台下有人偷偷刷手机&#xff…

2026/10/13 12:22:17 阅读更多 →
Qt国际化翻译完整实践:从tr()到动态语言切换

Qt国际化翻译完整实践:从tr()到动态语言切换

做Qt开发这么多年,遇到最多的问题不是功能写不出来,而是功能做完以后客户说看不懂。于是QT国际化翻译就成了绕不开的环节。表面上看,这事只是把界面文字换成英文、日文,真正做起来却涉及源码扫描、翻译文件管理、运行时加载、动态…

2026/10/13 12:22:17 阅读更多 →
华为+红帽双赛道:2026网工转型的破局之道

华为+红帽双赛道:2026网工转型的破局之道

1. 为什么2026年网工转型,我建议你押注"华为红帽"双赛道最近不少朋友私信问我关于2026年转行网络工程师(网工)的事,大家的焦虑点很一致:AI工具越来越强,初中级网工的活是不是要被替代&#xff1f…

2026/10/13 12:22:17 阅读更多 →
Modern.js 服务端编译核心 @modern-js/server-utils:TypeScript 编译、别名解析与原生 ESM 支持的源码级解析

Modern.js 服务端编译核心 @modern-js/server-utils:TypeScript 编译、别名解析与原生 ESM 支持的源码级解析

前端后端Web框架 【免费下载链接】modern.js A progressive web framework based on React and Rsbuild. 项目地址: https://gitcode.com/gh_mirrors/mo/modern.js 点击查看 免费下载 本文围绕 packages/server/utils/CHANGELOG.md 记录的能力演进,结合…

2026/10/13 12:22:17 阅读更多 →
基于SpringBoot+Vue的派出所健康档案管理系统设计与实现

基于SpringBoot+Vue的派出所健康档案管理系统设计与实现

选题背景 社会对公共安全的重视,派出所民警的工作压力日益增大,其健康状况备受关注。早期的健康档案管理方式效率低下,难以实现信息的实时共享和动态更新。本系统采用 Spring Boot 框架,结合前端技术和数据库技术,构建…

2026/10/13 12:22:17 阅读更多 →
EmbeddingGemma 2本地多模态嵌入模型部署与向量检索实战

EmbeddingGemma 2本地多模态嵌入模型部署与向量检索实战

1. 这个模型到底是什么:先把它的定位弄清楚拿到"EmbeddingGemma 2"这个名字,第一反应就是:这是个嵌入模型,740M参数规模,多模态,而且主打本地推理。这几个关键词放在一起,意味着它并不…

2026/10/13 12:21:16 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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 阅读更多 →