Delphi 无效指针操作

3

这里有几行在Delphi 7中运行的Delphi代码:

    var
      ptr:Pointer ;
    begin
      ptr:=AllocMem(40);
      ptr:=Pchar('OneNationUnderGod');
      if ptr<>nil then
        FreeMem(ptr);
    end;

运行此代码片段时,FreeMem(ptr)将会出现错误:“无效的指针操作”。如果我删除这句话:
     ptr:=Pchar('OneNationUnderGod');

如果没有错误发生,那么现在我有两个问题:

1.为什么会出现这种情况?2. 如果我必须使用Pchar句子,应该如何释放先前分配的内存?

非常感谢您的帮助!

3个回答

6
问题在于您修改了变量ptr中保存的地址。
您调用AllocMem来分配一个缓冲区,并使用ptr引用它,这一点很好。但是您绝不能改变ptr的值,即缓冲区的地址。而您确实改变了它。
您写道:
ptr:=AllocMem(40);
ptr:=Pchar('OneNationUnderGod');

第二行是问题所在。你已经修改了ptr,现在它指向了其他的东西(恰好是保存在只读内存中的字符串文字)。你已经失去了跟踪调用AllocMem分配的缓冲区的能力。你请求AllocMem为你分配了一块新的内存块,然后立即丢弃了那个内存块。
你可能想要做的是复制字符串。也许像这样:
ptr := AllocMem(40);
StrCopy(ptr, 'OneNationUnderGod');

现在我们可以放心调用 FreeMem,因为 ptr 仍然包含了调用 AllocMem 提供的地址。
ptr := AllocMem(40);
try
  StrCpy(ptr, 'OneNationUnderGod');
  // do stuff with ptr
finally
  FreeMem(ptr);
end;

显然在实际代码中,您会找到更好和更强大的方法来指定缓冲区长度,而不是硬编码数值。


在您的代码中,假设上述修复已应用,则检查ptr是否为空无需。AllocMem从不返回nil。AllocMem失败会导致异常被引发。


尽管如此,通常不会以这种方式操作字符串缓冲区。使用Delphi字符串是正常的。例如,如果您需要PChar与Interop一起使用,则可以使用PChar(str)创建一个str类型的PChar。

您说您必须使用动态分配的PChar缓冲区。也许确实如此,但我非常怀疑。


在Delphi中,AFAIR是strcOpy;-) ,也许StrLCopy会是更可靠的一般模式。 - Arioch 'The
@Arioch'The 感谢您的纠正。StrLCopy可能很好。但我认为我会始终使用字符串和PChar()。如果您分配了正确大小的缓冲区,则StrCopy有时可以使用。如果您已经调用了StrLen,那么Move就是我会使用的方法。 - David Heffernan
不,我只将StrLCopy视为安全限制,就在像AllocMem(const)这样的分配之后。在将许多代码从move(x,y,sizeof(y))转换为Unicode后 :-D - Arioch 'The
@Arioch 我更喜欢戴腰带或吊带。我认为两者都没有必要。StrCopy和StrLCopy的问题在于通常需要执行两次空终止符搜索。不过这些都有点无关紧要,因为PChar(str)更好。 - David Heffernan

2

我会尝试让你所做的更加明确。你似乎把变量的名称和它的值混淆了。然而,实际上 - 考虑到数值 - 你所做的是

 ptrA:=AllocMem(40);
 ptrB:=Pchar('OneNationUnderGod');
 if ptrB<>nil then 
     FreeMem(ptrB);

每次新分配内存的时候,都会覆盖之前分配的内存,这样你就可以释放另一个已经分配的指针。
您可以阅读一些函数的文档,例如StrNew、StrDispose、StrCopy、StrLCopy以及使用PChar字符串的示例代码,以了解一些处理方式。

2

这是因为您释放了静态内存,而这段内存并非动态分配的。事实上,不需要释放用于字面量的内存。只有动态分配的内存才需要释放。


1
但我使用AllocMem(40)创建了ptr,难道这个ptr指向的内存块不是动态分配的吗? - world peace
2
也许换句话说,楼主忽视了PChar赋值意味着ptr不再指向AllocMem分配的内存? - MartynA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接