你如何检查记录指针在 Object Pascal / Delphi 中是否没有值?

nei*_*rds 1 delphi pascal pointers

我正在尝试在 Delphi 中创建一个链表实现,但无法创建节点,因为我需要检查头指针是否为空。我现在使用的代码如下所示:

procedure LinkedList.addNode(newNode: Node);
var lastNode: Node;
begin
if pHead = nil then
  pHead := @newNode
else
   lastNode := peekLastNode(pHead^);
   lastNode.pNext := @newNode;
end;
Run Code Online (Sandbox Code Playgroud)

程序在添加一个元素后就冻结了,所以 nil 部分是无限期的问题。

这是整个程序:

program LinkedListImplementation;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;
type
  Node = record
    data: string;
    pNext: ^Node;
  end;
type
  LinkedList = class
    pHead: ^Node;
    function peekLastNode (currentNode: Node) : Node;
    function listToString(currentNode: Node) : String;
    procedure addNode (newNode: Node);
  end;

//the initial parameter for this function is LinkedList.pHead^
function LinkedList.peekLastNode (currentNode: Node) : Node;
begin
  if currentNode.pNext = nil then
    result := currentNode
  else
    result := peekLastNode(currentNode.pNext^);
end;

//produces string in form 'abc -> def -> ghi' from linked list
function LinkedList.listToString(currentNode: Node) : String;
begin
  if currentNode.pNext = nil then
    result := currentNode.data
  else
    result := currentNode.data + ' -> ' + listToString(currentNode.pNext^)
end;

//this uses helper method 'peekLastNode'
procedure LinkedList.addNode(newNode: Node);
var lastNode: Node;
begin
if pHead = nil then
  pHead := @newNode
else
   lastNode := peekLastNode(pHead^);
   lastNode.pNext := @newNode;
end;

var
  Strings: LinkedList;
  String1: Node;
  String2: Node;
begin
  try
    String1.data := 'abc';
    String2.data := 'def';
    Strings.Create();
    Strings.addNode(String1);
    Strings.addNode(String2);

    WriteLn(Strings.listToString(Strings.pHead^));
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 5

addNode(), 如果pHeadnil那么你将它设置为指向一个局部变量,如果不是nil那么你设置lastNode.pNext为指向另一个局部变量。这些局部变量在addNode()退出时超出范围,从而离开pHead/pNext悬空,以便下次尝试使用它们时它们指向无效内存。

Node实例添加到列表时需要使用堆分配,并且需要传递^Node指针而不是Node直接传递实例。

此外,addNode()有一个逻辑错误,因为它lastNode.pNext无条件地设置是否pHeadnil。如果PHEAD是nil那么lastNode没有分配任何东西。该else块缺少有关begin..end其操作的语句。

此外,您甚至没有LinkedList正确构建对象。 Strings.Create();需要Strings := LinkedList.Create();改为。

话虽如此,请尝试更像这样的事情:

program LinkedListImplementation;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  PNode = ^Node;
  Node = record
    data: string;
    pNext: PNode;
  end;

type
  LinkedList = class
  private
    pHead: PNode;
  public
    destructor Destroy; override;
    function peekLastNode(currentNode: PNode = nil): PNode;
    function listToString(currentNode: PNode = nil): String;
    function addNode(const data: String): PNode;
    procedure clear;
  end;

destructor LinkedList.Destroy;
begin
  clear;
end;

//the initial parameter for this function is LinkedList.pHead
function LinkedList.peekLastNode(currentNode: PNode) : PNode;
begin
  if currentNode = nil then currentNode := pHead;
  if (currentNode = nil) or (currentNode.pNext = nil) then
    Result := currentNode
  else
    Result := peekLastNode(currentNode.pNext);
end;

{ Alternatively:

function LinkedList.peekLastNode(currentNode: PNode): PNode;
begin
  if currentNode = nil then currentNode := pHead;
  Result := currentNode;
  if Result <> nil then
  begin
    while Result.pNext <> nil do
      Result := Result.pNext;
  end;
end;
}

//produces string in form 'abc -> def -> ghi' from linked list
function LinkedList.listToString(currentNode: PNode): String;
begin
  if currentNode = nil then currentNode := pHead;
  if currentNode = nil then
    Result := ''
  else if currentNode.pNext = nil then
    Result := currentNode.data
  else
    Result := currentNode.data + ' -> ' + listToString(currentNode.pNext);
end;

{ Alternatively:

function LinkedList.listToString(currentNode: PNode): String;
begin
  Result := '';
  if currentNode = nil then currentNode := pHead;
  if currentNode <> nil then
  begin
    Result := currentNode.data;
    while currentNode.pNext <> nil do
    begin
      currentNode := currentNode.pNext;
      Result := Result + ' -> ' + currentNode.data;
    end;
  end;
end;
}

//this uses helper method 'peekLastNode'
function LinkedList.addNode(const data: String): PNode;
begin
  New(Result);
  Result.data := data;
  Result.pNext := nil;
  if pHead = nil then
    pHead := Result
  else
    peekLastNode(pHead).pNext := Result;
end;

{ Alternatively:

function LinkedList.addNode(const data: String): PNode;
var
  currentNode: ^PNode;
begin
  currentNode := @pHead;
  while currentNode^ <> nil do
    currentNode := @((currentNode^).pNext);
  New(currentNode^);
  (currentNode^).data := data;
  (currentNode^).pNext := nil;
  Result := currentNode^;
end;
}

procedure LinkedList.clear;
var
  currentNode, nextNode: PNode;
begin
  currentNode := pHead;
  while currentNode <> nil do
  begin
    nextNode := currentNode.pNext;
    Dispose(currentNode);
    currentNode := nextNode;
  end;
end;

var
  Strings: LinkedList;
begin
  try
    Strings := LinkedList.Create();
    try
      Strings.addNode('abc');
      Strings.addNode('def');

      WriteLn(Strings.listToString());
    finally
      Strings.Free();
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)