Files
queue_exercise/调试记录.md
T
SCHOOL e542ebe8e1 顺序表:实现 q_addpro 任意位置插入,记录已知问题
1.c:
- q_addpro 完成平移 + 插入的基本逻辑(从后往前挪,避免覆盖未搬元素)
- 修掉 realloc 尺寸算错导致的堆越界(sizeof(q->max) → q->max * sizeof(int))
- 补上遗漏的写入动作 q->start[num] = x

仍存在的问题(详见 调试记录.md):
- 平移循环多搬一次,把垃圾值带进表
- 没有检查插入位置是否合法,非法位置会静默越界写
- q->length 从未初始化,但 q_add 的扩容判断在用它
- q_reduce / q_reducepro 未完成

新增 调试记录.md 记录以上问题与待办测试用例。
2026-09-17 20:56:14 +08:00

122 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 调试记录
记录顺表练习过程中遇到的问题和当时的想法。
---
## 2026-09-17 当前进度
| 函数 | 状态 |
|---|---|
| `q_init` | 可用(但见问题 3) |
| `q_add` | 可用 |
| `printall` | 可用 |
| `q_addpro` | 能跑,但有 bug(见问题 1、2) |
| `q_reduce` | 空函数,未写 |
| `q_reducepro` | 写了,未测试(见问题 4) |
---
## 问题 1:`q_addpro` 平移时多搬了一次,把垃圾值带进了表
**现象**:插入之后,数据末尾会多出一个来源不明的值。
**复现**:表长 3、元素 `1 2 3`,执行 `q_addpro(&q, 3, 666)`,
打印结果为 `1 2 3 666 3801155 ...` —— `3801155` 不是任何一次输入的数据。
**待查**:循环的**起点**取的应该是哪一个下标?
> 补充:同样的问题在表长 6 时也存在,只是那次垃圾值落到了打印范围之外,
> 所以没被发现。**同一个 bug,换个尺寸才现形。**
---
## 问题 2:`q_addpro` 不检查插入位置是否合法
**现象**:`q_addpro(&q, 11, 1919810)` 在表长只有 5 时被接受,
程序不报错、不崩溃,静默跑完。
**实际后果**:扩容后 `max = 8`(合法下标 0~7),但数据被写到了 **下标 11**。
也就是往不属于自己的内存里写了 4 格 —— **堆越界**。
**记住的教训**:
- 越界 ≠ 崩溃。Windows 上这类写坏通常无声无息,只在特定边界才炸。
- 防御性编程:函数应该先检查参数,发现非法就**立刻返回**,
并用返回值告诉调用方"我失败了"。
- 这几个函数都声明成 `int`,但从来没 `return` 过 —— 那个 `int` 就是留给这件事的。
**待定**:合法插入位置的范围是什么?(`num` 能不能等于表长?能不能负数?)
检测到非法之后,函数该怎么返回?调用方该怎么处理?
---
## 问题 3:`q->length` 从未被初始化
`q_init` 里只设了 `max`、`front`、`end`,**没有给 `length` 赋值**。
但 `q_add` 的扩容判断用的是 `q->length == q->max` ——
等于拿一个栈上的随机数来决定要不要扩容。
目前测试没踩到,是因为运气。换个输入就会出问题。
**待定**:`length` 和 `end` 到底是不是同一个东西?如果循环队列要用 `length`,
那它得先被管起来。
---
## 问题 4:`q_reducepro` 的平移方向
删除和插入的平移**方向是相反的**,但原理相通。
`q_reducepro` 目前写的是 `for (size_t i = num; i < q->end + 1; i++)`,
还没测过。另外注意 `size_t` 是无符号类型。
**待测**:
- [ ] 删 0 号位
- [ ] 删最后一个
- [ ] 删中间
- [ ] `*x` 里拿到的是不是被删掉的那个值
- [ ] 删除后表长有没有正确减少
---
## 待办的测试用例
- [ ] 插入到 0 号位
- [ ] 插入到末尾(`num == end`)
- [ ] 表"差一格满"时(`end == max - 1`)插入
- [ ] 非法位置:负数、大于表长
- [ ] 往空表里插入
---
## 环境和工具备注
- 源文件目前是 **GBK** 编码,PowerShell 里中文能正常显示。
(注意:不要再加 `-fexec-charset=GBK`,会转两次反而乱码)
- 编译命令:`gcc -Wall 1.c -o 1.exe`
- 本机 **没有装 ASan**(AddressSanitizer),想抓内存越界得用别的办法。
- `printall` 用的边界是 `q->end` —— 如果 `end` 本身不可信,打印出来的就是假象。
---
## 已经解决的(记录一下思路,别忘了)
**扩容时 `realloc` 的大小算错了**
写成了 `realloc(q->start, sizeof(q->max))`,而 `sizeof(q->max)` 是
"一个 `int` 占几字节"(4),不是"总共要几字节"。
正确写法是 `个数 × 每个的大小`。当时误申请到了 4 字节,
后面的数据全被堆的元数据覆盖,打印出来是一堆每次都不同的随机数。
> **识别技巧**:数据每次运行都不一样 → 读到的不是自己的数据,是别人的内存。
**忘了把 `x` 真正写进去**
平移做完了,但没执行插入动作,参数 `x` 从头到尾没被用过。
编译器的 warning 里其实点了名(`unused parameter 'x'`)。
> **识别技巧**:编译器说某个参数"没被用过",八成是漏写了什么。