1、到底什么是指针?  指针是一种数据类型,那么是否可以这样来理解:
  假设内存单元是一个一个的房间,内存地址是门牌号,房间里存放的是各种类型的数据;而指针呢,是否是一单独的内存(房间),他里面存储了指向某些房间(依据所存储的数据类型确定)的门牌号?2、VAR 声明变量之后,哪些类型的变量需要开辟一内存空间来保存一个指针(当然在没有赋值给变量前指针内存储NIL),然后再赋值给变量时再开辟新的内存空间保存数据,同时将数据区域的地址存储在指针内?3、这是TObject.ClassName的代码:
class function TObject.ClassName: ShortString;
{$IFDEF PUREPASCAL}
begin
  Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
end; 
。 如上:Self是个指针,由于指针不能加减,所以要转化为实际内存地址然后才能相加,那么:
 PPointer(Integer(Self) + vmtClassName)^ 为什么与Pointer(Integer(Self) + vmtClassName)不一样?区别在哪里?
 Integer(指针)是一个整型数,看来应该是指针所指向对象的基地址,那么,在VAR声明变量之后,如果没有赋值,这个结果是否应该为0?
 在上面的代码里,PPointer(Integer(Self) + vmtClassName),PPointer(Integer(Self) + vmtClassName)^,PShortString(PPointer(Integer(Self) + vmtClassName)^)都是指针,但由于是中间结果,是否编译器为其临时分配空间存储并自动回收空间
4、要获取某一内存区域内存储的数据,是否应该这样来处理?
   声明相同类型的变量以保存数据
   获取该内存区域的基地址
   依据基地址,转化成相应类型的指针
   取得数据如上,望不吝指教。

解决方案 »

  1.   

    vcshcn(黑天的猩猩) :   1 指针就是地址:理解成指针里面存储的是地址是否具体些?
       2 要看具体类型:我做过尝试,发现CHAR类型的变量,指针即数据,数据即指针;STRING型的就分开了。
      

  2.   

    一般来说可以明确变量所存储的内存大小的指针和你所说的变量是一样的,通常情况访问此类型的数据不需要一个指针来处理,这些类型可以是 ShortString, Integer, Char, Byte, Word, real 等。相反的,如字符串 String, WideString 等这样不是可以确定长度的数据类型,通常情况下声明之后是一个指针,实际的数据和这个指针不在一起,编译器需要通过这个指针才能够访问到数据。
    不知道有没有听明白?
      

  3.   


       1 指针就是地址:理解成指针这个变量的值就是某一量的地址   2 要看具体类型:这就是编译器进行的工作之一。简化了程序员的工作。
    3
    PPointer是指向指针的指针
    Pointer是一般的指针(当然其中的内容也可以是指针)
    假如有关系C-->B-->A
    要找到A,可以使用Pointer(B),也可以使用PPointer(C)4、可以
      

  4.   

    zhxfzhxf1(zhxfzhxf1) :
      Pointer是无类型指针,PPointer是无类型指针的指针,但是为什么
      Pointer(Integer(Self) + vmtClassName)与PPointer(Integer(Self) + vmtClassName)^不相等呢?
      

  5.   

    首先,我想在讨论指针之前说明两个概念问题:指针和指针变量指针其实就是内存地址的别名,是一个表示地址的值
    而指针变量就是存放指针这种类型值的变量,在OP语言中规定占用4个字节----具体为什么要占用这么大的内存空间我想和指针这种类型值的格式有密切关系在明确了着两个概念以后,我们才可以进行讨论:
    首先在我们编写代码来实现某些功能的过程中,当我们看待我们写的代码的时候可以有两种视角来思考我们所写的代码的意义,一个就是编译器角度,另外一个就是语言角度。在编译器看来所有的一切都是地址,但在具体开发环境开来,所有的一切就是他们在内存中实际的存在内容。两种视角产生的差异最后完全通过编译器和IDE自身来进行协调,例如当如下申明时:var
      I:Integer;  //编译器看到的I就是一个地址值,并且这个地址值是自己产生的。但IDE看到的I则是一个内容不确定的整数值,和当前它在内存中实际的内容完全一致----而我们在平时写代码的时候大部分是使用后面那个视角去看待我们写的代码
    ....明白了这个东西以后,我们来看看到底什么是指针变量(楼主的第一个题目应该是问什么是指针变量,而不是指针----因为指针就是地址的别称),在IDE看来,指针变量就是内存中一个占据4个字节,里面存放着一个指针的内存空间,而在编译器看来,它同样是一个地址(也可以说指针,但为了防止混淆,最好别这么叫!)....IDE的视角一般也就是我们常使用的看待代码的方式!至于问题二----Delphi中的引用/值模型中的引用类型变量都是先分配指针变量空间,然后赋予具体指针值的....PPointer(Integer(Self) + vmtClassName)是二级指针,是指针的指针 
    Pointer(Integer(Self) + vmtClassName)是一级指针,所以内容肯定不一样了Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
    上面这个语句是进类的VMT中获取类名字串----Self的值本应该是堆上对象实体的首地址,但由于这里是类方法,所以Self类似一个类引用类型变量,存放的值和对象实体中的vptr的值一样,然后加偏移量vmtClassName得到VMT中类名字串的存放地址,最后取得类名!至于你说的Integer(SomePointer)是否为零,在没有具体分配值的情况下,如果是全局的就为0,否则为不确定数值....然后临时变量的空间问题个人认为是在当前方法的栈上临时分配,在离开作用域后直接释放....由于任意存取当前进程空间中某个地址上的数据内容的时候我们根本不知道这个地址存放数据的类型,所以这样做虽然可以实现,但没有任何实际意义,所以必须:
    1.实现申明一个类型确定的变量
    2.存放数据
    3.获取前面申明变量的地址
    4.获取数据内容
      

  6.   

    其他都没什么好说的,主要谈一下PPointer和Pointer的不同。
        假设有:PA->Data。意思是指针PA指向了数据区Data。并且现在知道PA本身的地址为A(即Integer(PA),但是我们假设不知道PA而只已知A),那么如何通过A得到Data呢?方法是使用:
        PPointer(A)。此时可看作得到一个临时指针Ptemp,它指向了Data。如果再施加Ptemp^,那么就得到了Data。很显然,Pointer(A)<>Ptemp^,因为Pointer(A)实际上是得到了PA。
        我们看:
    class function TObject.ClassName: ShortString;
    {$IFDEF PUREPASCAL}
    begin
      Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
    end; 
    这是一个类方法,所以其中Self是类本身,那么Integer(Self)实际是得到虚拟方法表(VMT)的基地址,再加上偏移vmtClassName,则得到类名字符串指针所在地址。
        对照上面的说明,可以将A看作Integer(Self) + vmtClassName,Data看作类名字符串。因此PPointer(Integer(Self) + vmtClassName)就得到了一个指向类名字符串Data的指针,再施加运算^,就得到Data的内容。因为此时Data是一个(类名字符串指针,PShortString类型),所以这时得到的是一个实际内容为ShortString的无类型指针,最后用PShortString强制转化即可。    对于上述的“PPointer(A)可看作得到一个临时指针Ptemp,它指向了Data”你可能有疑问:Ptemp=PPointer(A)=PA=Pointer(A)对吧?的确是这样的,也就是说PPointer(A)=Pointer(A)。实际上,PPointer和Pointer在本质上没有不同,它们得到的是相同的数据,唯一的区别是,再对它们施加^运算后,前者仍然得到一个指针,而后者得到一个无类型数据;这样,使用前者方法在某些时候可以更加方便的实现数据类型转化。我们看如下使用Pointer的方法可以得到和PPointer相同的结果:
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);      
      public
        class function ClassName: ShortString; //重新声明ClassName
      end;var
      Form1: TForm1;implementation{$R *.dfm}class function TForm1.ClassName: ShortString;
    begin
      Result := PShortString(Pointer(Integer(Self) + vmtClassName)^)^; //使用Pointer
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      ShowMessage(ClassName); //显示‘TForm1’
    end;————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  7.   

    “VAR 声明变量之后,哪些类型的变量需要开辟一内存空间来保存一个指针”这句话有点意思。不是开辟内存空间来保存指针,而是声明一个指针来引用内存空间。Delphi中除原生指针类型外,还有以下几种指针类型:
    String(Long)
    WideString
    Array(Dynamic)
    Object
    Interface
    其中Object因为不会自动释放,所以不会自动初始化为nil。
    Array在SetLength需要合法的信息,所以一定会被初始化为nil。
    其它类型需要自动释放,也一定会被初始化为nil。其中String和WideString都是用指针实现的值语义,在WideString进行赋值时可能会导致一个释放/分配操作(释放原空间,分配新空间)。而String则实现了COW语义,赋值和操作时只会操作引用计数,把空间分配和数据复制推迟到第一次改变字符串中的字符时。其它都是引用语义,赋值操作不会导致内存分配和复制。
      

  8.   

    谢谢各位热心回答!
      大致明白了,但对于
      PPointer(A)=Pointer(A) 而不是
      PPointer(A)^=Pointer(A),还是有些困惑
      

  9.   

    又回去看了一下,又有新的疑问:class function TObject.InstanceSize: Longint;
    begin
      Result := PInteger(Integer(Self) + vmtInstanceSize)^;
    end;
    上面为什么可以直接将地址转换成指针,然后取值,是由指针变量所指向内存区域所存储的数据类型所决定?
    那么有没有一个规则?
      

  10.   

    toyjoy(异根) :指针可以直接相加?
          应该是取得指针的基地址,然后再加上偏移地址,再强制转换为指针吧?
      

  11.   

    之所以这样作是因为Object Pascal中只允许对指针调用Inc和Dec,而不允许进行计算,所以才转换为整数进行地址计算。而在32位扁平内存模式下,一个指针的长度恰好与一个整数的长度相等,否则就会出错。
    其实这段代码更好的写法是:
    type
      TByteAry = array[0..65535] of Byte;//只要你不打开界限检查,数组长度多少都行
      PByteAry = ^ TByteAry;
    begin
      Result = PInteger(@(PByteAry(Self)^[vmtInstanceSize]));
    end;
    这样可以不依赖于指针长度与整数长度的关系。
      

  12.   

    1、对于
      PPointer(A)=Pointer(A) 而不是
      PPointer(A)^=Pointer(A),还是有些困惑PPointer(A)^取得的是地址A中保存的指针(它又指向了另一个地方),而Pointer(A)是取得指向地址A的指针。2、class function TObject.InstanceSize: Longint;
    begin
      Result := PInteger(Integer(Self) + vmtInstanceSize)^;
    end;
    因为虚拟方法表在vmtInstanceSize处保存的本身就是一个整数,即InstanceSize的值,而不是指针。这和ClassName不同。————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————