我是Pascal的新手,目前正在使用指针。我有2个记录,其中一个包含2个指向另一个记录类型的指针。
type
WaypointRef = ^Waypoint;
PathRef = ^Path;
Waypoint = record
id: integer;
Name: string;
pathRefs: array of PathRef;
end;
Path = record
distance: integer;
WaypointRefA, WaypointRefB: WaypointRef;
end;
所有的航点都保存在一个数组中。现在,当我试图读出一条路径的值时,我得到了神秘的结果:
writeln(waypoints[0].pathRefs[0]^.distance);
writeln(waypoints[1].pathRefs[0]^.distance);
两者应该打印相同的值,但实际上它们没有。然而,更神秘的是,即使我尝试以下操作:
writeln(waypoints[0].pathRefs[0]^.distance);
writeln(waypoints[0].pathRefs[0]^.distance);
writeln(waypoints[0].pathRefs[0]^.distance);
我得到两个不同的值。(正确的一个- 173 -第一次,然后2所有的时间之后。)
waypoints[0].pathRefs[0]^
总是指向同一个地址,所以我很困惑。我希望有人知道这个问题。
EDIT:2似乎是默认值,因为如果我在创建路径时没有保存任何值到“distance”,它也会返回2。
编辑2:这里的代码的航点和路径创建。我认为一定是有一个失败。我现在可能是混乱的设计,因为程序内的程序。我只是试验。
procedure buildWaypoint(Name: string);
procedure addWaypoint(w: Waypoint);
var
lngth: integer;
begin
lngth := Length(waypoints);
SetLength(waypoints, lngth + 1);
waypoints[lngth] := w;
end;
var
w: Waypoint;
begin
w.id := id;
id := id + 1;
w.Name := Name;
addWaypoint(w);
end;
procedure buildPath(waypointRefA, waypointRefB: WaypointRef; distance: integer);
procedure addPath(pRef: PathRef);
procedure addPathToWaypoint(pRef: PathRef; wRef: WaypointRef);
var
lngth: integer;
begin
lngth := length(wRef^.pathRefs);
SetLength(wRef^.pathRefs, lngth + 1);
wRef^.pathRefs[lngth] := pRef;
end;
begin
addPathToWaypoint(pRef, pRef^.WaypointRefA);
addPathToWaypoint(pRef, pRef^.WaypointRefB);
end;
var
p: path;
begin
p.distance := distance;
p.WaypointRefA := waypointRefA;
p.WaypointRefB := waypointRefB;
addPath(@p);
end;
2条答案
按热度按时间qybjjes11#
有两种情况可能导致这种意外行为:
1.如果
waypoints[0]
和pathRefs[0]
的数组类型属性由getter方法支持:那么这些方法就有可能产生副作用,从而导致问题的发生。(* 显然,这里不是这种情况 )。1.如果指针指向"无效内存"位置:那么内存被其他代码覆盖可能会导致值更改。( 而这是你的问题 *。)
在堆栈上声明要添加的路径:
wRef^.pathRefs[??]
指向调用堆栈中较高的地址。您需要确保指向堆上的内存。您可以使用动态内存分配例程来实现这一点:一米三氮一x一米四氮一x一米五氮一x一米六氮一x
Documentation关于动态内存分配例程。
如何更改代码的示例:
h7appiyu2#
您正在将wayPointRefA和wayPointRefB传递给buildPath过程。该过程应该在这两个航点之间创建一条路径,然后将其添加到这两个航点的路径数组中。所有业务逻辑都很好。
问题就出在这里,你还没有考虑到生命周期,你的wayPointA和wayPointB将持有一个指向P的指针,而P存在于buildPath过程的堆栈帧中,这意味着在你真正创建了路径P(表示wayPointA和wayPointB之间的路径),并将指向P的指针添加到这两个waypoint的路径数组中之后,P超出了作用域,指向P的指针变成了一个悬空指针,我认为程序不会崩溃,因为当你调用另一个过程或函数时,你的程序再次拥有了P曾经所在的那部分内存,但现在那部分内存被用于完全不同的用途。P不再存储在那里,这就是为什么当你试图访问pathref的字段时会得到无意义的值。
不幸的是,Pascal编译器接受了这些垃圾代码。不幸的是,Pascal中没有拥有和借用内存的概念,也没有生命周期注解。在Rust @P中(或者更确切地说&P)意味着你借用了数据,你必须指定生存期注解,因为P没有足够长的生存期,你的代码将无法编译。你也可以让路点拥有路径数据,这样你的代码就不会编译,因为@P(Rust中的&P)不是一个被拥有的类型。
如果你在Rust中编写程序,你将把P Package 在一个引用计数器(Rc)中,因为你有2个拥有相同路径数据的航点。
在Pascal中,你可以使用new关键字(许多其他语言也使用这个关键字)把path放到堆中。这样,路点就不会有一个悬空指针。不过,要记住你是循环引用路点和路径的,所以你需要非常小心内存管理。如果可以的话,最好避免出现路径和路点循环引用的情况。