【问题标题】:delphi invalid pointer operationdelphi无效指针操作
【发布时间】:2014-01-02 09:03:39
【问题描述】:

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

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

运行此代码 sn-p 时,FreeMem(ptr) 将引发错误:'invalid pointer operation'。如果我删除这句话:

     ptr:=Pchar('OneNationUnderGod');

那么不会发生错误。现在我有两个问题,

1.为什么会这样? 2.如果一定要使用pchar语句,应该如何释放之前分配的内存?

非常感谢您的帮助!

【问题讨论】:

    标签: delphi pointers memory-management runtime-error


    【解决方案1】:

    问题是您正在修改变量 ptr 中保存的地址。

    您调用 AllocMem 来分配一个缓冲区,您使用 ptr 引用该缓冲区。这么多就好了。但是你绝不能改变 ptr 的值,即缓冲区的地址。而你确实改变了它。

    你写道:

    ptr:=AllocMem(40);
    ptr:=Pchar('OneNationUnderGod');
    

    第二行是问题所在。您已经修改了 ptr 并且现在 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 为 nil。 AllocMem 永远不会返回 nil。 AllocMem 失败会引发异常。


    话虽如此,以这种方式对字符串缓冲区进行操作并不常见。使用 Delphi 字符串是正常的。如果您需要一个 PChar,例如与互操作一起使用,请使用 PChar(str) 创建一个,其中 str 是字符串类型。

    您说您必须使用动态分配的 PChar 缓冲区。也许是这样,但我非常怀疑。

    【讨论】:

    • 德尔福中的 AFAIR 是 strcOpy ;-) 或许 StrLCopy 通常会是更可靠的模式
    • @Arioch'The 感谢您的更正。 StrLCopy 可能很好。但我想我总是使用字符串和 PChar()。如果您分配正确大小的缓冲区,则 StrCopy 有时会很好。如果你调用了 StrLen,那么 Move 就是我会做的。
    • 不,我只是将 StrLCopy 视为安全限制,就在上面的 AllocMem(const) 之类的分配之后。在将很多代码(如 move(x, y, sizeof(y)) 转换为 Unicode 之后:-D
    • @Arioch 我更喜欢佩戴腰带或牙套。我认为两者都不需要。 StrCopy 和 StrLCopy 的问题是通常您执行两个空终止符搜索。不过因为 PChar(str) 更好,所以这一切都没有实际意义。
    【解决方案2】:

    它崩溃是因为您正在释放非动态分配的静态内存。根本不需要释放文字使用的内存。只有动态分配的空闲内存。

    【讨论】:

    • ,但是我使用AllocMem(40)创建了ptr,这个内存块ptr不是动态分配的吗?
    • 也许,换句话说,OP忽略了PChar分配意味着ptr不再指向AllocMem分配的内存?
    【解决方案3】:

    我会尽量让你所做的更明确。您似乎将变量的名称与其值弄错了。然而实际上 - 考虑到价值观 - 你所做的是

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

    每个新赋值都会更改值,覆盖前一个赋值,因此您释放了另一个已分配的指针。

    您可以阅读 StrNew、StrDispose、StrCopy、StrLCopy 等函数的文档和示例代码,以了解使用 PChar 字符串的一些模式。

    【讨论】:

      猜你喜欢
      • 2012-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      相关资源
      最近更新 更多