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

4.1 KiB
Raw Blame History

调试记录

记录顺表练习过程中遇到的问题和当时的想法。


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')。

识别技巧:编译器说某个参数"没被用过",八成是漏写了什么。