gpt4 book ai didi

delphi - 帕斯卡指针改变其指向值

转载 作者:行者123 更新时间:2023-12-02 08:20:01 25 4
gpt4 key购买 nike

我对 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]^

总是指向同一个地址,因此我很困惑。我希望有人知道这个问题。

编辑:2 似乎是默认值,因为如果我在创建路径时没有将任何值保存到“距离”,它也会返回 2。

EDIT2:这里是航路点和路径创建的代码。我想一定有失败的时候。我现在可能会因为程序里面的程序而设计困惑。我只是在尝试。

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;

最佳答案

有两件事可能会导致这种意外行为:

  1. 如果您有由 getter 方法支持的 waypoints[0]pathRefs[0] 的数组类型属性:那么这些方法可能具有侧面- 会导致问题的影响。 (显然这里的情况并非如此)。
  2. 如果您的指针引用“无效内存”位置:则其他代码覆盖内存可能会导致值发生变化。 (这就是你的问题。)

您要添加的路径已在堆栈上声明:

var
p: path; //<-- Stack variable
begin
...
addPath(@p);
end; //<-- When you leave the method the stack variable is no longer valid.
  • 由于此代码,您的 wRef^.pathRefs[??] 指向调用堆栈上较高的地址。
  • 当您调用其他方法时,相同的内存会用于其他目的。
  • 并且这些值可以更改。

您需要确保指向堆上的内存。您可以通过使用动态内存分配例程来完成此操作:NewDisposeGetMemFreeMem

编辑

Documentation关于动态内存分配例程。

如何更改代码的示例:

procedure addPathToWaypoint(pRef: PathRef; wRef: WaypointRef);
var
lngth: integer;
LpRefOnHeap: PathRef;
begin
lngth := length(wRef^.pathRefs);
SetLength(wRef^.pathRefs, lngth + 1);
New(LpRefOnHeap); //Allocate heap memory
LpRefOnHeap^ := pRef^; //Copy data pointed to by pRef to heap
wRef^.pathRefs[lngth] := LpRefOnHeap; //Hold reference to an address that won't
//become invalid when stack unwinds.
end;

注意:您必须弄清楚何时何地处置动态分配的内存。

<小时/>

EDIT2 添加一个简单的控制台应用程序来演示问题。

program InvalidUseOfStackVar;

{$APPTYPE CONSOLE}

type
PData = ^TData;
TData = record
Value: Integer;
end;

var
GData: PData;

procedure SetData;
var
LData: TData; //Stack variable will no longer be valid when routine exits.
begin
LData.Value := 42; //The initial value pointed to by GData
GData := @LData; //The global var will continue to point to invalid memory after exit.
end;

procedure ChangeStack;
var
//This is written to have the same stack layout as the previous routine.
LData: TData;
begin
LData.Value := 777; //This unintentionally changes data pointed to by the global var
end;

begin
SetData; //Sets GData, but GData points to an address on the call stack
Writeln(GData^.Value); //Writes 42 because that's what was on the stack at the time of the method call.
ChangeStack; //Updates the stack variable to a different value
Writeln(GData^.Value); //Now writes 777 because GData points to the same location in memory, but the
//data at that location was changed.
Writeln(GData^.Value); //Note: calling the Writeln method above also changes the stack.
//The only difference is that it is less predictable for us to determine
//how the stack will be changed.
Readln;
end.

关于delphi - 帕斯卡指针改变其指向值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26926014/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com