二、用配置好的VSCode实战做一道算法题
多说无益,直接开干
以这道题为例
一道用来练手的算法题
P5720 【深基4.例4】一尺之棰
P5720 【深基4.例4】一尺之棰
题目描述
《庄子》中说到,“一尺之棰,日取其半,万世不竭”。第一天有一根长度为 a 的木棍,从第二天开始,每天都要将这根木棍锯掉一半(每次除 2,向下取整)。第几天的时候木棍的长度会变为 1?
输入格式
输入一个正整数 a,表示木棍长度。
输出格式
输出一个正整数,表示要第几天的时候木棍长度会变为 1。
输入输出样例 #1
输入 #1
100输出 #1
7说明/提示
数据保证,1 ≤ a ≤ 109。
0. 建立基本工作空间,打开VSCode,新建源文件


备注 · 随便打开一个空文件夹即可,这个文件夹就是我们写这道算法题的地方

1. 自信编码,谁都不爱
说明 · 然后根据题目要求,享受你的编码过程,你会发现,你有语法错误,拓展会帮你纠正,写
scanf等函数调用时,拓展会有补全和参数信息提示,虽然在AI盛行的当下,这算古法编程,但这也确实是科班出身的必经之路。

说明 · 然后凭着直觉写下这道题的解法,自信满满地提交。


反例 · 我靠,劳资居然也会错?
提示 · 接下来,终于轮到我们配置好的VSCode出场了,让我们通过一步步调试来看看,我们第一印象的这种解法错在哪里?为什么不对?
2. 开始调试自己的程序
2.1 在循环处打断点

左边那个小红点就是断点:程序跑到这一行会停下来等你。点一下行号左侧的空白就能打上,再点一下取消。
2.2 把程序送进调试器
点右上角那个向下的小箭头(就在「运行」图标旁边),会弹出一个菜单,里面有两项:

选下面那一项 —— 调试 C/C++ 文件。VSCode 会先让你选一个调试配置,它已经自动扫到了你本机的 gcc:

点下去,程序就跑起来了。
注意 · 这里有个所有人的第一反应都会踩的坑
你并没有生成
launch.json。没有配置文件,程序怎么也跑起来了?往下看,这件事正是这一节最该弄明白的地方。
2.3 喂给它数据,然后看它停在哪
程序起来之后不会自己动,它在等你输入。点一下下方终端,把样例里那个 100 敲进去,回车:
说明 · 输完之后,左侧多了些东西
你会发现左侧面板里冒出了
变量、监视、调用堆栈、断点四栏,而且程序很明显停在了while循环那一行 —— 那一行整个被高亮成了黄色。这就是断点生效的样子。

2.4 单步:让它一次只走一行
现在点工具条上那个拐着弯的箭头(悬停显示「单步调试 (F11)」),代码就会往下走一行:
说明 · 代码一行一行地执行,变量一格一格地变
每点一次,左边的
length和day就跟着变一次。自己试着多点几下,盯着那两个数看 —— 这就是「变量在程序里怎么变」这件事第一次变得肉眼可见。

2.5 找到问题:day 是 6,不是 7
一直点到循环跳出去,停在了 printf 那一行。这时候看左边的 变量 栏:
变量 | 值 | 你以为的 |
|---|---|---|
|
|
|
|
|
|

循环确实跑了 6 次,但 day 是从 0 开始数的。 从第一天算起一共 7 天,程序只数出来 6 —— 答案当然是错的。
找到原因就好办了。先让它继续跑完,退出调试:

2.6 回头看看:launch.json 去哪了?
先把这件事说透 —— 因为它是这一整节里最容易被误解的地方。
上一篇里,你亲手生成了一份 launch.json,还逐个字段读过。所以到了这一篇,你多半会以为刚才那一路调试,是 VSCode 读了那份配置才跑起来的。
不是。 这次它连文件都没生成,你真去 .vscode/ 目录里翻,只有 tasks.json。调试面板标题栏写的也是「没有配置」。
原因在 C/C++ 扩展身上:它内置了一份兜底配置。当它发现你没有 launch.json、或者配置列表是空的时候,它不等你配置,直接按自己的默认值把调试器拉起来 —— 就用当前打开的那个源文件。这就是菜单里那句「调试 C/C++ 文件」的含义:不用你配置,我来处理这一份文件。
直接调试(默认兜底)
触发方式:
运行→调试 C/C++ 文件它用谁:当前正在编辑的那个源文件,
${file}launch.json:不生成、不存在,标题栏显示「没有配置」编译:先按
tasks.json里group.isDefault为true的那个任务编一遍适合:随手试一段代码、跟教程走一遍。快,但什么都留不下
用 launch.json
触发方式:
F5,或标题栏那个绿色三角它用谁:
launch.json里program字段写死的那张路径launch.json:必须是现成的,且能对上一个configurations条目编译:按配置里的
preLaunchTask去执行对应任务,名字对不上就报错适合:一个项目反复调试。慢一点,但配置能跟着文件夹走,换台电脑打开就是同一套
重点 · 一句话记住它们的区别
「调试 C/C++ 文件」是「帮我调这一个文件」;
launch.json是「我规定好以后都这么调」。
前者省事,后者省心 —— 你现在写的这点代码用哪个都行,但等你手里有一个正经项目,那就必须得上配置了。
那 launch.json 到底怎么来?在运行和调试面板里点「创建 launch.json 文件」,VSCode 会把上面那份兜底配置原样写成一份文件交给你,之后你就可以在上面逐字改了。
2.7 改一行,再验一遍
错误原因已经清楚了:循环里数的是「第二天往后」,第一天没人数。 所以在循环外面补一句 day++:

存盘,按 F5 再走一遍。这次 day 停在 7,符合预期 —— 提交给洛谷试试:

冷静一下:刚才到底发生了什么
代码跑完了,AC 也拿到了。但在关掉这篇文章之前,回头看一眼刚才那一小段路 —— 你会发现它和你以为的不太一样。
第一版代码,VSCode 一个字都没报。没有红线,没有波浪线,Ctrl + Shift + B 编译得干干净净。编辑器认可它,编译器认可它,只有洛谷那一排绿色的 AC 不认可它。
因为你的程序语法完全正确,只是逻辑错了。
这是初学者最容易卡住的一个坎,也是本文最想让你记住的一件事:
出错类型 | 谁会发现 | 你看到什么 | 怎么修 |
|---|---|---|---|
语法错误 | 编辑器 / 编译器 | 红线、波浪线、终端里一串 | 顺着报错改就行,最省事 |
逻辑错误 | 只有你自己 | 什么都没报,结果是错的 | 只能靠调试,靠盯着变量一步一步看 |
顺手复习一遍编译器的四个参数:
参数 | 它替你做了什么 | 少了会怎样 |
|---|---|---|
| 让报错带颜色 | 一整屏白字,读起来费劲 |
| 往可执行文件里塞进行号、变量名 | 断点是灰色的,点不动 —— 没有调试信息,gdb 只能看到一堆内存地址 |
| 打开所有常用警告 | 一些明显的可疑代码(比如赋值写成比较)它不会再提醒你 |
| 开优化,让程序跑得更快 | 你反而不该要它:优化会打乱代码和行号的对应关系,调试时看到的位置会对不上 |
${env:DEBUGINFOD_URLS}=''; & 'C:\Users\Soleaf\.vscode\extensions\ms-vscode.cpptools-1.34.4-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' ...一长串,看着就头大。但你把参数一个个挑出来读,会发现每个参数都能对上一样东西:
--stdin=对应你敲进去的100该往哪儿送,--debugExe=后面跟的就是gdb.exe,--interpreter=mi表示它用的是机器接口。
而你什么都没配置,它却知道该送哪个文件、该调哪个 gdb —— 因为你点的那一下「调试 C/C++ 文件」,就是这份兜底配置的开关。
前两篇文章讲的那个规律,在这一行里又出现了一次:图形界面不是魔法,它只是把你的配置翻译成了一条很长的命令,然后替你敲下去。 只不过这一次,那份「配置」是它自带的。
该轮到你上手了
把 100 换成这几个数,重新跑一遍,看看 day 也跟着变:
你输入 | 正确答案 | 你的程序输出 |
|---|---|---|
| 1 | ? |
| 7 | ?(就是你刚才那个) |
| 2 | ? |
| 30 | ? |
第二行你已经验证过了。第 1 行和第 3 行是专门给你挖的坑 —— 想想为什么输入 1 的时候答案应该是 1 而不是 0。
顺手再改一个地方:while (length != 1) 这行里,如果长度本来就小于 1 会怎样?把 int length 换成 float 试试?这些改动都不需要重学任何东西 —— 你已经有了工具,改完按 F5,看变量,就这么简单。
实在想不出来,点开看提示
while 的条件是 length != 1,只要长度不等于 1 就继续循环。
输入 1 的时候,条件从一开始就是假 —— 循环一次都不会执行,day 还是初始的 0,程序直接打印 0。但题目说得很清楚:第一天木棍长度就是 1,答案应该是 1。
这就是那个 day++ 为什么必须补在循环外面 —— 它管的是第一天,循环里那次自增管的是第二天往后。两件事,别混。
写在最后
摘要 · 你真正拿到手的东西
不是「学会了一道洛谷题」。这道题你明天就会忘掉。
你真正拿到手的是:代码跑不对的时候,你知道该往哪儿看。
你可以让程序停在任何一行,看着length和day一格一格地变,亲手确认是哪一步跟你想的不一样。你不再需要盯着代码发呆、猜哪里错了,也不再需要到处插printf然后一条条删掉。
走到这里,一条完整的链路已经握在你手里了:
一条完整的链路: 〇 · 认识编译器(装 MinGW、配 PATH)→ 一 · 搬进 VSCode(tasks.json + launch.json)→ 二 · 实战一道题(写代码 → WA → 调试找 bug → AC)
第〇篇解决的是「程序是怎么跑起来的」;
第一篇解决的是「怎么让工具替我跑」;
这一篇解决的是「跑错了怎么办」。
三件事凑齐,你就不再是那个「照着步骤抄一遍、跑出 Hello World 就不知道下一步该干嘛」的人了。你是一个能自己找出问题在哪的人 —— 这是往后的所有语言、所有框架、所有项目都绕不开的底子。
基础不牢,地动山摇。
别急着追新技术。你刚才用的这些东西 —— 编译器、断点、单步、看变量 永远都有用,相信我,这套流程会贯穿你计算机学习的整个生涯。
参考文献
题目和工具链的官方来源,需要查证细节时来这里:
