RT,有这样的定义
type
TPointData = array of Pointer;
end;var FData : TPointerData;
    i : integer;
   
在程序里面动态添加数组元素setlength(Fdata,length(FData) + 1);
FData[length(FData) - 1] := pointer(i);如果是整形的则没问题,之后可以正常访问FData[i]的值如果是将字符串赋给指针则之后出现乱码
var str : string;
setlength(Fdata,length(FData) + 1);
FData[length(FData) - 1] := pointer(str);
在程序段中showmessage(string(FData[length(FData) - 1]));是正常的,但我在其它地方用到这个数组时,就出现乱码如果是静态数组,则直接
new(Fdata[i]);
然后赋值搞得我都糊涂了,具体要怎么做才能正常显示???我在动态数组中NEW()会出错,不知道为什么。

解决方案 »

  1.   

    这句代码很奇怪:
    FData[length(FData) - 1] := pointer(str);Pointer是无类型的,对于Delphi自动管理的类型(如string,array,record),强制使用Pointer转换并不会增加变量的引用计数,等到变量被回收了,再使用指针来访问就可能会得到垃圾数据。
      

  2.   

    string变量的实际内容在heap中分配,stack里只有个指针,delphi使用引用计数来维护string的生存期。当使用显示转换将string类型转成其它指针类型的时候,并不会增加它的引用计数,生存期结束后该释放就释放了。在其它地方再访问的时候如果只是乱码就算运气不错了,直接出内存访问错误都很正常。解决方法个人推荐使用PChar来存取,当然用PString来弄也可以你的FData[n]是Pointer类型,New的原形是System._New:
    function _New(size: Longint; typeInfo: Pointer): Pointer;
    当你调用New(PTypeVar)的时候,会隐含传入SizeOf(PTypeVar^)、TypeInfo(PTypeVar^)两个参数,其中后一个是供Initialize用的。你认为SizeOf(Pointer^)应该是多少,编译器能猜出来么?
      

  3.   

    其实我用TObject也可以,只是知道要怎么搞,就像listbox 有这样的功能
    items.addobject();这个方法,任何类型的都可以加进去,到底是什么原理?
    还有就是
    setlength(Fdata,length(FData) + 1); 
    FData[length(FData) - 1] := pointer(i); 
    这样又为什么可以呢?解决方法个人推荐使用PChar来存取,当然用PString来弄也可以 ------------------------------------------------------放到数组里?FData[length(FData) - 1] := pchar(str); 
    一样的....
      

  4.   

    Orz
    当使用显示转换将string类型转成其它指针类型的时候,并不会增加它的引用计数,生存期结束后该释放就释放了
    如果你不知道PChar和StrNew/StrDispose的话,那还是用PString和NewStr/DisposeStr吧……
      

  5.   

    type
      TarrayVariant = array of PChar;
    FarrayVariant  :TarrayVariant ;
     
    For i := 0 to 1o do
    begin
          DriveString := '测试' + inttostr(i);
          SetLength(FarrayVariant,Length(FarrayVariant) +1 );
          FarrayVariant[Length(FarrayVariant)  -1 ] :=  strNew(PChar(DriveString)) ;
    end;FarrayVariant 为全局变量,在其它代码段中调用时,这样是可以正常显示,但是要怎么释放这些内存?StrDispose 不知道怎么用另外一个就是刚刚说的,这种要以什么类型的形式存入数组中?
    谢谢!!
      

  6.   


    你用个LIST 去添加试下
      

  7.   

    StrNew和StrDispose用法很简单:
    var
      p: PChar;
    begin
      p := StrNew(PChar('hello'));
      StrDispose(p);
    end;
      

  8.   

    多類型的話,可以用 array of variant;
    對于基礎類型,可以通過varType取得。若是復雜類型(如class),無法直接獲得,若是對象,可通過所記錄的地址(類型為varLongWord),訪問負偏移地址vmtTypeInfo可以取得類型信息,如PPointer(Integer(v[i]) + vmtTypeInfo)^。
      

  9.   


    这是我的释放的代码,运行到某些元素下标时会报错,无效指针、、不知为何 
    for i := low(FList) to High(FList) do 
    begin
      StrDispose(pchar(Flist[i]));
    end;
    起先也是考虑用变体类型,可是里面要存放类对象。
    我想先试一下指针数组的方法可行不
      

  10.   

    还有就是
    type 
      TarrayPointer = array of Pointer;
    var Flist : TarrayPointer ;这种可否采用这种方法,将类对象存入到数组中?
    就是先申请内存,将对象拷入内存块,然后再赋给数组,能否行得通不?
      

  11.   

    用Pointer也可以,但不必拷貝對象,只需記錄對象地址即可。需要知道對象類型,可以聲明一個record,元素包括 類型,值或者地址用variant也是可以的,因為記錄的只是指針而已。
      

  12.   

    我试着总结一下,如果要实现你的目标(数组元素可以是整型、字符串或对象实例),需要考虑下面几个问题:1. 如何将某个变量的值保存到数组内?
    对于值变量(如Integer、Int64,作为局部变量、参数时分配在栈上),最稳妥的方法是重新分配一块内存保存这个值。如:
    var
      p: PInteger;
      n: Integer;
    begin
      n := 2;
      New(p);     // 使用New手工分配内存时,所传递的指针参数必须是有类型的,这样编译器才知道要给变量分配多大的内存
      p^ := n;    // 将变量n的值拷贝到指针p所指向的内存的值
      Dispose(p); // 手工释放内存
    end;而对于引用类型(如string、对象实例),只要保存引用的地址就可以了。如:
    var
      obj: TObject;
      p: Pointer;
    begin
      //...
      p := obj;
    end;这里顺便提一下,Delphi里面有些类型(如string、array)是由编译器自动维护引用计数的,如果使用无类型的Pointer则需要注意这一点(可能会引用无效的值)。2. 如何知道某个数组元素的类型?
    很显然,如果数组定义成array of Pointer,我们是没办法知道元素所代表的实际类型的。明白了上面两点,问题就简单多了。我们先看看最简单的方法:
    type
      TDataArray = array of Variant;这种方法可以保存Delphi内大多数的简单类型的值,而且无需管理内存,但美中不足的是Variant不能直接保存对象实例的地址。当然,这个时候可以按照楼上的变通一下,采用某种类型来保存对象实例的地址,使用时再强制转换即可。另有一种方法就是使用TVarRec:
    type
      TDataArray = array of TVarRec;
    这种方式支持Delphi的部分复杂类型(如Class),但需要手工分配及释放内存,而且操作上比较麻烦,需先根据VType判断类型,且不能想Variant那样直接赋值。还有一种方法就是自己封装一个结构。当然,如果可行的话,我建议使用对象来封装。如:TDataObject = class
    protected
      function GetAsString: string; virtual; abstract;
    public
      property AsString: string read GetAsString;
      //...
    end;TInteger = class(TDataObject)
    //...
    end;TDataArray = array of TDataObject;  // 如果使用TObjectList更方便。
      

  13.   

    谢谢楼上热心的兄弟。现在 好像可以了。而对于引用类型(如string、对象实例),只要保存引用的地址就可以了。如: 
    var 
      obj: TObject; 
      p: Pointer; 
    begin 
      //... 
      p := obj; 
    end; 
    这种方法是不是不用自己去分配和管理内存?还有就是
     var FarrayVariant : array of pointer;
    For i := 0 to 1o do 
    begin 
      DriveString := '测试' + inttostr(i); 
      SetLength(FarrayVariant,Length(FarrayVariant) +1 ); 
      FarrayVariant[Length(FarrayVariant)  -1 ] :=  strNew(PChar(DriveString)) ; 
    end; 
    For i := 0 to 1o do 
    begin 
      StrDispose(Pcahr(FarrayVariant[i]));
    end; 
    这个释放的操作,怎么内存好像没有任何变化?就是不管执不执行这个操作,内存没有变化那最后,我是不是可以采用这种方式来保存字符串和类对象?而对于引用类型(如string、对象实例),只要保存引用的地址就可以了。如: 
    var 
      obj: TObject; 
      p: Pointer; 
    begin 
      //... 
      p := obj; 
    end; -----------
    非常感谢!!
      

  14.   

    1. 对于对象实例来说,obj实际上是一个有类型的指针,所以
    var
      obj: TObject;
      p: Pointer;
    begin
      obj := TObject.Create;
      try
        p := obj;         // p和obj指向了同样的地址,使用TObject(p)和obj效果相同
      finally
        FreeAndNil(obj);  // 现在p所指向的内存已经被释放,再使用p可能会导致内存访问错误。
      end;
    end;严格的来说,声明指针变量时,编译器已经为这个指针变量*本身*分配了内存。给这个指针赋值时(p:=obj;),实际上是把obj所引用的对象实例的地址保存到这个指针变量内。(呵呵,也就是说:指针变量的值保存的是某个对象实例的地址)。但字符串和对象不同(由于字符串由Delphi自动管理创建和释放,引用计数为0时自动释放),需要分配内存:
    procedure Test;
    var
      str: string;
      p: PString;  // 声明为PString,可以利用string的引用计数;如果为PChar,使用StrNew,则会重新拷贝内容。
    begin
      str := IntToStr(12345); // 此时字符串的引用计数为1
      New(p);
      p^ := str;              // 此时字符串的引用计数为2
      Dispose(p);             // 此时字符串的引用计数为1
    end; // 离开作用域后字符串引用计数为0,自动释放内存。2. 内存没有变化是指哪块内存?调用Dispose或StrDispose只负责释放指针所指向的那块内存,并没有把指针置为nil,如果再使用这个指针,*可能*会导致无效访问(当然,因为长字符串的内容分配在堆上,当这块内存还没有被覆盖时,数据还是正确的,但这块内存区域应该已经标记为不可用了(个人猜测))。3. 前面已经说了,使用无类型的Pointer,无法知道元素的实际类型。
      

  15.   

    -_-
    1.那这种操作是不是有必要的?
    var FarrayVariant : array of pointer; 
    For i := 0 to 1o do 
    begin 
      DriveString := '测试' + inttostr(i); 
      SetLength(FarrayVariant,Length(FarrayVariant) +1 ); 
      FarrayVariant[Length(FarrayVariant)  -1 ] :=  strNew(PChar(DriveString)) ; 
    end; 
    有没有必要进行手动释放?
    For i := 0 to 1o do 
    begin 
      StrDispose(Pcahr(FarrayVariant[i])); 
    end; 2.对于对象实例来说,obj实际上是一个有类型的指针,所以 
    var 
      obj: TObject; 
      p: Pointer; 
    begin 
      obj := TObject.Create; 
      try 
        p := obj;        // p和obj指向了同样的地址,使用TObject(p)和obj效果相同 
      finally 
        FreeAndNil(obj);  // 现在p所指向的内存已经被释放,再使用p可能会导致内存访问错误。 那如果不释放这个对象,在其它地方访问是不是正常的?
      end;          
    end;3.我释放前面申请的内存,并把数组长度设为0 在任务管理器里看不到内存使用的变化呢,