Pascal外部访问违规问题:原因及修复方法求助
二叉树初始化时的空指针访问问题
运行代码
program Version_als_Kompilett; uses SysUtils; type tRefBinBaum = ^tBinBaum; tBinBaum = record wert: integer; li: tRefBinBaum; re: tRefBinBaum end; function initTree(): tRefBinBaum; var Baum: tRefBinBaum; begin new(Baum); Baum^.wert := 30; //random(100); if (Baum = nil) then writeln('Baum ist nil'); if (Baum^.li = nil) then writeln ('Baum links nil') else writeln('Baum links : ' + IntToStr(Baum^.li^.wert)); if (Baum^.re = nil) then writeln('Baum rechts nil') else writeln('Baum rechts : ' + IntToStr(Baum^.re^.wert)); if (Baum^.li^.li = nil) then writeln('Baum links links nil') else writeln('Baum links links : ' + IntToStr(Baum^.li^.li^.wert)); if (Baum^.li^.re = nil) then writeln('Baum links rechts nil') else writeln('Baum links rechts : ' + IntToStr(Baum^.li^.re^.wert)); if (Baum^.re^.li = nil) then writeln('Baum rechts links nil') else writeln('Baum rechts links : ' + IntToStr(Baum^.re^.li^.wert)); if (Baum^.re^.re = nil) then writeln('Baum rechts rechts nil') else writeln('Baum rechts rechts : ' + IntToStr(Baum^.re^.re^.wert)); initTree := Baum; end; var Testsubjekt: tRefBinBaum; begin Testsubjekt := initTree(); readln(); end.
报错情况
运行时触发内存访问错误,问题出在以下代码行:
if (Baum^.re = nil) then writeln('Baum rechts nil') else writeln('Baum rechts : ' + IntToStr(Baum^.re^.wert));
疑问
- 为什么会出现这个错误?左子节点的判断似乎可以正常工作,但右子节点不行。
- 我该如何修复?我是Object-Pascal的新手。
(注:使用Lazarus IDE,术语翻译:Baum=树,Wert=值,rechts=右,links=左)
问题原因
这是未初始化指针的随机值问题。你用new(Baum)创建了根节点的指针并分配了内存,但Baum^.li和Baum^.re这两个子节点指针并没有被显式初始化为nil。
在Object-Pascal中,new仅为记录分配内存空间,不会自动初始化内部的指针字段——这些指针会保留内存中的随机垃圾值。左子节点的判断没报错只是巧合,那个随机值刚好是nil或者指向了程序可访问的内存;而右子节点的随机值是无效地址,访问时直接触发了内存访问错误。
修复方案
1. 显式初始化子节点指针
在创建根节点后,手动将左右子节点指针设为nil,确保它们的状态确定:
function initTree(): tRefBinBaum; var Baum: tRefBinBaum; begin new(Baum); Baum^.wert := 30; // 显式初始化左右子节点为nil Baum^.li := nil; Baum^.re := nil; // 后续判断逻辑可正常执行 if (Baum = nil) then writeln('Baum ist nil'); if (Baum^.li = nil) then writeln ('Baum links nil') else writeln('Baum links : ' + IntToStr(Baum^.li^.wert)); if (Baum^.re = nil) then writeln('Baum rechts nil') else writeln('Baum rechts : ' + IntToStr(Baum^.re^.wert)); // ... 其余判断代码不变 initTree := Baum; end;
2. 修复深层子节点的访问逻辑
当前代码中访问Baum^.li^.li这类深层节点时,没有先判断父节点是否有效。如果Baum^.li是nil,直接访问Baum^.li^.li会再次触发崩溃,正确写法应该先校验父节点指针:
// 示例:修复左左子节点的判断逻辑 if (Baum^.li <> nil) then begin if (Baum^.li^.li = nil) then writeln('Baum links links nil') else writeln('Baum links links : ' + IntToStr(Baum^.li^.li^.wert)); end else writeln('Baum links ist nil,无法访问左左子节点');
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

