//我要做一个DLL,供其它语言使用!
//在从主调程序申请了内存后,把地址传递给DLL程序,发现被传递过去的Str的地址与主调中的Str地址不一致
//结果可想而知,提示指针操作无效!
//请问如何才能正确处理!
//很郁闷......
var
  Str:PChar;
begin
  GetMem(Str,255);//我已经在主调程序中把内存申请,便于在主调中释放
  Showmessage(Inttostr(Integer(Str)));//申请的内存地址首址
  TestFunc(Str);
  FreeMem(Str,255);
end;//DLLfunction TestFunc(Str:PChar):boolean;
begin
  Showmessage(Inttostr(Integer(Str)));//传递过去的首址,发现地址不一样
  Str:='Hello';
end;

解决方案 »

  1.   

    奇怪的是,在主调程序内部写2个过程,来进行PChar传递地址就一致!
      

  2.   

    首先要明白'Hello'在delphi里会默认当一个const的字符串处理,
    它的内存我没仔细研究过到底在哪分配,但只有2个可能,一个就是栈里,另外一个就是堆里。
    如果是堆里那按照AnsiString里介绍,它的释放由引用计数决定(String为指针,且在这个指针前面有4个字节的引用计数和4个字节的字符串长度),如果是在栈里,那函数调用完毕就会被清栈。
    再看dll里的这句代码Str:='Hello';
    将一个指针指向了一个新的内存,所以带来的问题是,你原来分配的内存在这句代码后就已经没办法再释放了。
    而这个指针重新指向的内存却已经不是你自己来管理的了 ,所以会带来的问题会是
    255个字节内存别泄漏,并且FreeMem(Str,255);会报内存相关错。
    你需要将这句代码改成。
    Str:=StrPCopy(Str,'Hello');
      

  3.   

    不知道你的主程序里是否也是这样写,如果也这样写,相信也会有问题存在。
    如果改成Str:=StrPCopy(Str,'Hello'); 还有错误,那有可能是函数调用惯例问题。
      

  4.   

    他的问题应该是在 STR 的赋值问题上,传递了字符串指针后,又重新改了STR的指针.导致释放问题.  在主调程序里PCHAR传递,应该是传递指针,没有再对改变指针变量的指向,所以没有出错.DELPHI里面 字符串变量指针是放在栈上的,字符串肯定是放在堆里的.不然不可能有2G容量这个说法
      

  5.   


    //DLL
    //我就是这样一个小程序,在主调函数中申请内存资源,并把首址传给DLL,让DLL把相应的字符串填写完毕后,我在主程序中读取,并释放资源!
    //大家都是怎么写的啊,能否给个例程
    function TestFunc(Str:PChar):boolean;
    begin
      Showmessage(Inttostr(Integer(Str)));//
      Str:='Hello';//这样写会改变
    end;
      

  6.   

    function TestFunc(Str:PChar (*默认传递Str会被复制一份,所以Str此时的地址已经不再是调用者的交赋的值,只是这个指针仍然指向同一个地址,换句话说 这个Str与调用者的Str的值是一致的,但是其内容地址是不一样的*) ):boolean;
    begin
      Showmessage(Inttostr(Integer(Str)));//传递过去的首址,发现地址不一样(*如果发现这里不一样,则有可能两边取值的方式不一样,或者参数传递错误*)
      Str:='Hello';(*这个则只修改了作为参数的副本(本地变量)的指向并不对调用者当中相应的作为参数的变量造成影响*)
    end;
    var
      Str:PChar;
    begin
      GetMem(Str,255);//我已经在主调程序中把内存申请,便于在主调中释放
      ZeroMemory(Str,255); //这里使用API (*注意:仅Win2k以上操作系统才有此API,在Delphi当中为兼容低版本系统自己做了实现*)
      CopyMemory(Str,PChar('Test1'),5); //这里使用API (*注意:仅Win2k以上操作系统才有此API,在Delphi当中为兼容低版本系统自己做了实现*)
      ShowMessage(str);
      Showmessage(Inttostr(Integer(Str)));//申请的内存地址首址
      TestFunc(Str);
      ShowMessage(str);
      FreeMem(Str,255);
    end;测试一
    function TestFunc(Str:PChar):boolean;
    begin
      Showmessage(Inttostr(Integer(Str)));//传递过去的首址,发现地址不一样
      Str:='Hello';
    end;测试二
    function TestFunc(Str:PChar):boolean;
    begin
      Showmessage(Inttostr(Integer(Str)));//传递过去的首址,发现地址不一样
      CopyMemory(Str,PChar('Hello'),5); //这里使用API (*注意:仅Win2k以上操作系统才有此API,在Delphi当中为兼容低版本系统自己做了实现*)
    end;
      

  7.   

    前面我已经提过很多回了,指针作为参数,特别是没有特别约定的情况下一定要传递一个可以表示已分配内存大小或者数据的多少的参数.即,此例当中应当为:var
      Str:PChar;
      Size: LongWord;
    begin
      Size := 255;
      GetMem(Str,Size );//我已经在主调程序中把内存申请,便于在主调中释放
      Showmessage(Inttostr(Integer(Str)));//申请的内存地址首址
      TestFunc(Str,Size);
      FreeMem(Str (*,255 此参数可以不需要,而且最好不需要,否则前面申请时大小的变化与这里不匹配会导致问题*));
    end;
    function TestFunc(Str:PChar; var Size: LongWord):boolean;
    var
      LocalString: String;
    begin
      Showmessage(Inttostr(Integer(Str)));//传递过去的首址,发现地址不一样
      LocalString := 'Hello';
      //Str:='Hello';
      CopyMemory(Str,PChar(LocalString),Min(Size,Length(LocalString)) (*在size不足时,仅以Size为准,以防溢出 *));
    end;
      

  8.   

    function TestFunc(Str:PChar (*默认传递Str会被复制一份,所以Str此时的地址已经不再是调用者的交赋的值,只是这个指针仍然指向同一个地址,换句话说 这个Str与调用者的Str的值是一致的,但是其内容地址是不一样的*) ):boolean; 
    ------------------------------------------------
    换句话说 这个Str与调用者的Str的值是一致的,但是其内容地址是不一样的,实在理解不了!指向的地址一样,而其内的数据不一样???是不是DLL内的内存管理器又单独为其分配了一个空间啊
      

  9.   

    Str的值,即Str指向的内容首地址
    Str的内容,即变量本身,一个四字节数据