这标题听起来既像技术复盘又像博客重启。实际上它就是我这两周的真实状态一边看着系统盘空间变红一边打开了丢下很久的 C 语言代码。过去这些年主要在写脚本和业务逻辑C 里最基础的指针和字符串越用越生。重拾 C 的那天晚上我先把 “VSCode配置c/c环境” 的热搜翻了一遍再顺手把“清理C盘”和“c语言程序设计”放进了同一个待办清单。这个组合看起来奇怪但实操下来发现很合理C 语言要编译、要看终端输出系统必须有一块干净的环境C 盘满了会让整个开发流程都变得黏黏糊糊。这篇文章没有套路完全按我真实踩过的路子来写适合那些学过 C 但丢了很久、想在 VSCode 里重新跑起 C 程序、或者正被 C 盘空间问题拖累的人拿来就能照着做。1. 为什么这场“C 的再续”要从清理C盘和开发环境同时开始1.1 “C”既是编程语言也是系统环境我以前一直觉得学 C 语言就只是语法问题顶多把指针啃明白。但真正重开项目的那天我体会到一个残酷现实语言学习是连贯的运行环境更是。当时的笔记本上C 盘已经红了接近一年编译器路径也是乱糟糟的VSCode 打开 .c 文件后代码提示整个罢工想编译一个 hello world竟然要先解决一堆环境问题。很多人一搜“C”这个热词会同时看到“c语言程序设计”和“清理c盘空间”。看起来毫无关联背后其实有一条共同逻辑重拾一门老技术首先要有能安心折腾的环境。C 语言的工具链不像现代脚本语言那么“自带”处理器、编译器、编辑器、文件权限哪一环出问题都会直接打断学习节奏。我也不想再做一个半途而废的重启所以决定先把系统这块“地”整干净再一门心思回到代码本身。1.2 给这次重启定一个不会崩的执行计划把目标拆成可执行的小段是我这次最正确的决定。我没有直接去刷算法题而是先把环境、语法、小练习分开确保每天都有正反馈。我把重拾 C 分成三个阶段第一阶段搞定电脑空间和开发环境第二阶段把字符串、循环、文件读写这些高频语法重新过一遍第三阶段用题目练手。这样安排的理由很实际如果环境没配好再简单的代码也会因为“编译器找不到”或“终端编码乱码”而让人急躁如果语法没捡起来直接刷题又要在报错里耗掉所有热情。先扫清环境障碍再让代码跑起来整个过程的成就感会高很多。这几个月里每天早上用半小时写一段 C 小程序下午偶尔做一两个 PTA 风格的练习题晚上留时间整理遇到的坑。没有把时间表排得过满但两周后我已经能比较流畅地完成字符串逆序输出、冒泡排序和文件读取这类练习了。2. 给 C盘 大扫除先清理系统盘空间再谈编译环境2.1 C盘满了别急着下“清理大师”先看空间被谁吃了C 盘满这个话题几乎天天有人搜“c盘满了怎么清理”。大多数人第一反应是找第三方“c盘清理大师”但踩过几次坑后我更推荐先自己判断。Windows 系统盘最容易膨胀的区域是用户缓存目录、软件更新残留、休眠文件和临时文件。打开资源管理器配合专门分析工具两三分钟就能定位大头。你可以用 WizTree、TreeSize 或系统自带的存储感知去扫描按文件大小排序后直接看到到底是哪个文件夹占了几个 GB。在手工清理时比较安全的路径是系统临时目录和用户临时目录。在“运行”窗口输入%TEMP%会打开当前用户的临时文件夹里面的日志和缓存一般可以删除C:\Windows\Temp是系统临时目录也需要定期清理但删除时最好让窗口以管理员权限打开。我见过有人在 C 盘根目录看到 Windows.old就在不清楚的情况下直接删结果导致无法回退系统版本。如果确认系统已经稳定运行且不需要回退再通过“磁盘清理”工具勾选“以前的 Windows 安装”去删除而不要手滑乱删其它系统目录。2.2 实测有用的清理组合系统清理命令与文件迁移下面这段是我自己在 Windows 上用的清理流程整体安全而且省事。打开“开始”菜单输入 cleanmgr选择 C 盘它会把可清理项列出来。如果想直接在命令行里呼出可以执行cleanmgr /d C。选中“临时文件”“缩略图”“回收站”这些明显安全的项目让系统去算实际空间。这时候不要勾选“下载文件夹”除非你确认里面没有安装包否则很容易事故。如果休眠功能对你意义不大可以在管理员终端执行关闭休眠命令来释放hiberfil.sys占用的几个 GB 空间。是否执行取决于你平时是否依赖“快速启动”和“休眠恢复”。我使用的指令是powercfg /h off执行后休眠文件会直接消失普通关机重启不受影响。只是要注意笔记本用户如果在乎合盖后的睡眠体验需要谨慎决定。对下载文件夹、桌面和文档里的超大文件我更倾向把它们搬到一个专门的扩展卷或大容量 U 盘而不是直接删除。把视频工程、虚拟机镜像这类大件从用户目录迁走后C 盘空间会肉眼可见地松一口气以后重装系统也不至于丢数据。2.3 扩容 C盘可以但要先处理文件系统错误空间清理完之后如果发现确实不够用有人会选择第三方分区工具来合并相邻分区也就是给 C 盘扩容。这里我必须提醒一句千万不要直接操作一个有文件系统错误的分区否则可能连盘都认不出来。有一次我用 DiskGenius 尝试把空闲空间扩给系统盘结果提示“本地磁盘I检测到文件系统错误$bitmap中有标记”。这个错误本质上表示目标分区的索引信息已经不一致如果强行继续轻则合并失败重则大量文件损坏。经验做法是先修复再扩容打开管理员命令提示符对报错的那个分区执行chkdsk I: /f它会扫描并修复文件系统错误。修复完成后再重新打开分区工具执行扩容风险会低很多。如果报错的是 C 盘本身记得先关机进 Windows PE 环境再检查或者让它生成重启后修复计划。总之分区扩容属于“动系统底层”的操作要有备份意识不要事到临头才发现重要资料还在同一个盘里。3. 重新配置 VSCode 的 C/C 环境让代码提示不再“罢工”3.1 编译器选型为什么我选了 MinGW-w64VSCode 本身只是编辑器真正让 C 代码能编译运行的是先装入 GCC 编译器。Windows 下的主流选项有两个方向一个是安装 Visual Studio 使用 MSVC适合 Windows 相关开发另一个是安装 MinGW-w64配合 GCC 使用。我这次选择 MinGW-w64原因是它轻量、不占太多 C 盘空间而且和 VSCode 的 C/C 扩展协作得比较顺。下载时我比较建议选择带有 posix 和 seh 标识的版本它对新线程模型和异常处理的支持更好。装好后的第一件事是找到安装目录里面会有一个 bin 文件夹路径类似D:\mingw64\bin。把这个目录加入系统 PATH 环境变量保存后重新打开终端执行gcc --version验证。如果提示“gcc 不是内部或外部命令”大概率是 PATH 没配对或者终端没有重新加载。这里有个老经验安装路径尽量别放在带空格的目录比如C:\Program Files\MinGW容易出现工具链解析路径的隐性坑我习惯直接放到C:\mingw64或D:\mingw64。3.2 VSCode 中新建工程与编译任务VSCode 里跑 C 程序不能只点一下“运行”需要先创建编译任务。这一步劝退了不少新手其实它只涉及 VSCode 工作区里的.vscode/tasks.json。先随便建一个后缀为 .c 的源文件比如hello.c然后在项目的.vscode文件夹下面新建tasks.json。下面是一份我在单文件练习场景下常用的配置它会调用 gcc 把当前打开的 .c 文件编译成同名 .exe{ version: 2.0.0, tasks: [ { label: Build C File, type: shell, command: gcc, args: [ -g, -stdc11, -Wall, ${file}, -o, ${fileDirname}/${fileBasenameNoExtension}.exe ], group: { kind: build, isDefault: true }, problemMatcher: { owner: c, fileLocation: [relative, ${workspaceFolder}], pattern: { regexp: ^(.*):(\\d):(\\d):\\s(warning|error):\\s(.*)$, file: 1, line: 2, column: 3, severity: 4, message: 5 } } } ] }写完这份配置后按CtrlShiftB就能编译当前文件。如果终端里没有报错会在同一目录下生成 .exe 文件。想调试的话还要给.vscode/launch.json写一份调试配置把路径和 preLaunchTask 对应上这样按 F5 会先自动编译再启动调试器。初次配置调试器最怕路径拼错我建议先编译成功一次再把生成的 exe 路径填进去能少走很多弯路。3.3 代码提示“罢工”的修复法配置 VSCode 后最容易遇到的问题是.c文件没有任何代码提示函数名、宏定义统统不补全。这样困扰源于 C/C 扩展的 IntelliSense 还不知道该用哪个编译器和头文件路径。可以点右下角语言模式确认文件已被识别为 C然后在命令面板搜索“C/C: Select IntelliSense Mode”选择基于 gcc 的模式。如果还是没提示就手动生成c_cpp_properties.json把编译器路径填对并让 includePath 包含项目目录。我也不建议一上来就同时装太多 C 语言插件。实测结果装官方 C/C 扩展和 Code Runner 基本就够用。Code Runner 的好处是能一键运行小练习但它在环境变量、编译参数上默认逻辑比较简单正式研究算法时还是用 tasks 里的 gcc 命令更透明。4. 重拾 C 语言必备语法字符串、循环与文件读写4.1 while 与 do-while 的差别其实用一次就容易记住语法忘掉以后最常纠结的两个循环是while和do-while。刚开始我还专门去查“c语言while和do-while区别”看到一堆定义后反而更晕。后来我给自己总结了一句话while 是先看门再进门do-while 是先进门再看门。写成代码能体现这种差别的是“至少要执行一次”的场景。比如要读取用户输入直到遇到退出条件用 do-while 就会利落很多int num; do { printf(输入一个正数输入0退出); scanf(%d, num); } while (num ! 0);这里如果写成 while就得在循环外先单独读一次输入逻辑很别扭。而另一个常见坑是scanf后残留的换行符会影响下一次读取所以写交互式小程序时我会多留意把输入缓冲清干净或者直接用fgets再解析。4.2 指针和字符串从被劝退到能看懂的两个关键认知重拾 C 的过程里指针是绕不过去的一道坎。过去我觉得指针特别玄后来发现只要抓两个点就容易很多一是数组名在很多场景下会“退化”成指向首元素的指针二是字符串本质上是字符数组末尾有一个隐藏的\0作为结束标记。看下面这段char s[] hello; char *p s; // p 指向数组第一个字符 printf(%c\n, *p); // 输出 h printf(%c\n, *(p1)); // 输出 e这个例子能解释很多问题。字符串变量不是直接拿来就能随便改的如果定义成char *p hello这里的字符串字面量可能存储在只读区尝试修改很容易崩溃。而数组定义char s[] hello是在栈上分配了可修改空间。初学阶段先把数组和数组指针的关系理清再接触二级指针、链表的时会舒服得多。4.3 文件读写操作代码一套可以复用的标准模板很多练习一旦涉及“c语言文件读写”就容易在文件指针上翻车。文件读写的标准流程只有四步打开、读写、判断是否成功、关闭。我常用fopen打开文件用第一参数指定路径第二参数指定模式“r”是读取文本“w”是写入文本“rb”“wb”对应二进制模式。下面这个例子是读取整个文件并输出#include stdio.h int main(void) { FILE *fp fopen(data.txt, r); if (fp NULL) { perror(打开文件失败); return 1; } char line[256]; while (fgets(line, sizeof(line), fp) ! NULL) { printf(%s, line); } fclose(fp); return 0; }初学者常犯的问题包括文件不存在时没有判断返回值、打开成功后忘记 fclose 导致文件占用、读取路径写错导致找不到文件。fgets比gets安全太多了它限制最大读取长度不会因为超长内容直接让栈崩溃。如果需要把整份文件倒序输出可以先把内容逐行读进二维数组再反过来打印这是一个较好的阶段性练习。5. 用三道拿来就能练的题目把写代码的手感找回来5.1 字符串逆序输出的几种思路热词里有一个很典型的练习“字符串逆序输出C”竞赛题和 PTA 经常出。做法其实不复杂将字符串当作字符数组在头尾各放一个指针或下标交换字符直到中间位置。手写版如下#include stdio.h #include string.h void reverse_string(char s[]) { int i 0; int j (int)strlen(s) - 1; while (i j) { char tmp s[i]; s[i] s[j]; s[j] tmp; i; j--; } } int main(void) { char s[] hello; reverse_string(s); printf(%s\n, s); return 0; }我自己写这道题时的第一个坑是没有意识到字符串结尾的\0直接用sizeof(s)计算长度结果把结尾标记也当作字符串的一部分输出出现乱码。所以除非是固定长度字符数组否则求长度应该用strlen。5.2 冒泡排序慢归慢但对理解双层循环很有用“冒泡排序 C语言”是另一个高频搜索。虽然它的效率在后端场景里并不高但作为练手题它能让你把双层循环和交换操作练扎实。我这里的实现如下void bubble_sort(int a[], int n) { for (int i 0; i n - 1; i) { for (int j 0; j n - 1 - i; j) { if (a[j] a[j 1]) { int tmp a[j]; a[j] a[j 1]; a[j 1] tmp; } } } }写这道题的重点是内层循环的j n - 1 - i因为每一轮都会把当前最大值放到末尾下一轮没必要再去比较已经排好的尾部。这个优化也让代码不是简单照抄而是真正理解背后的原因。5.3 快速排序从“背模板”到能自己写出来快速排序是算法基础里要求较高的一道一旦能在纸上画出分区过程对递归和分治的理解也会明显变好。我的快速排序写得比较“顺手”选中中间位置的值作为基准然后左指针向右找大于等于基准的数右指针向左找小于等于基准的数一旦满足条件就交换#include stdio.h void quick_sort(int a[], int left, int right) { if (left right) return; int pivot a[(left right) / 2]; int i left; int j right; while (i j) { while (a[i] pivot) i; while (a[j] pivot) j--; if (i j) { int tmp a[i]; a[i] a[j]; a[j] tmp; i; j--; } } quick_sort(a, left, j); quick_sort(a, i, right); }要注意的是如果每次都固定取最左边元素做基准对于已经有序的数据会退化得很严重极端情况下复杂度变成 O(n²)。这里取中间元素或者使用随机基准会稳得多。递归函数一定要先写退出条件否则你会在栈溢出里浪费很多时间。6. C语言重学路上的报错速查与排错思路6.1 环境类问题编译器找不到、代码提示不出、脚本无法运行把这段时间所有排坑记录整理出来最不值得浪费时间的其实就是环境类问题。现象常见原因解决思路终端提示 gcc 不是内部或外部命令MinGW 没有被加入 PATH检查安装目录把bin路径加进系统 PATH并重开终端VSCode 中 C 文件没有代码提示IntelliSense 模式或编译器路径错误安装官方 C/C 扩展选择 gcc-x64 的 IntelliSense 模式检查c_cpp_properties.json提示无法加载npm.ps1因为禁止运行脚本PowerShell 执行策略限制在管理员终端执行Set-ExecutionPolicy -Scope CurrentUser RemoteSigned后再试编译成功但终端中文乱码源码编码与终端编码不一致统一使用 UTF-8或在编译参数里根据实际环境配置字符集关于 npm 那个问题其实和 C 语言本身无关但很多人重装开发环境时会遇到。它不是 Node.js 坏掉而是 PowerShell 默认脚本执行策略比较严格。如果你确实需要通过 npm 脚本命令来构建项目这个设置能让当前用户执行本地脚本但平时还是不建议全面放开执行策略。6.2 代码运行类问题从 scanf 卡住到文件读取空指针代码运行方面的坑就更多了但大多数可以用“先怀疑输入再怀疑指针”的套路来定位。比如scanf一直不结束多半是输入流里有不可见字符或者格式控制字符串里混入了额外空格比如程序一启动就崩溃第一步检查是不是对空指针调用strcpy或fclose又比如文件明明在桌面程序却说打不开十有八九是相对路径与执行目录不一致解决方法是直接用绝对路径或先打印当前工作目录。我曾经调试一个多文件读取程序崩溃点诡异到每次都不同折腾很久才发现是其中一个fopen成功后没有判断 NULL后续读取直接使用空文件指针。所以我现在写代码都会习惯性地做空指针检查哪怕看起来繁琐实际上能在后面省下大量时间。6.3 排错顺序很重要别让“猜”浪费时间最后想分享一个排错顺序的经验遇到报错先读编译器给出的第一条信息而不是急着改代码。很多人看到一大段英文报错就慌了直接把所有警告当错误处理最后越改越乱。实际上 gcc 的第一行往往精确指向了源文件名、行号和列号先定位到那一行再去理解是什么操作触发了问题会容易得多。如果真遇到看不懂的报错我的习惯是把报错原文复制出来抽掉具体路径后再去查。不要急着在全网乱搜搜索结果质量参差不齐反而容易被过时的配置信息带偏。在我的重学阶段光是把报错读明白这一件事就让我成功排掉了 70% 以上的问题。C 语言不是门槛环境的坑和情绪上的急躁才是真正的门槛。