代码片段:
var i:integer;
s:pchar;
begin
i:=65;
s:=pchar(@i);
end;
其中的s最后结果为A如果把i换成175849那么转换出来的s是怎么计算出来的?
不是很懂pchar的意思,请高手帮忙!

解决方案 »

  1.   

    把I,S    add watch,然后通过memory dump一看便知
    i: $41 $00 $00 $00 s: $41 
      

  2.   

    pchar是指针
    指向变量I的地址,65是A的ASC码十进制,十六进制是$41
    @是取地址符转贴
    ---------------------------------------------------------------------------------浅谈Object Pascal的指针大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人 产生误解,似乎只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今 的Object Pascal,可以说在指针运用上,丝毫不会逊色于C语言的指针。以下内容分为八个部分,分别是
    一、类型指针的定义
    二、无类型指针的定义
    三、指针的解除引用
    四、取地址(指针赋值)
    五、指针运算
    六、动态内存分配
    七、字符数组的运算
    八、函数指针
    一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:
    int *ptr;
    char *ptr;
    与之等价的Object Pascal是如何定义的呢? 
    var
    ptr : ^Integer;
    ptr : ^char; 
    其实也就是符号的差别而已。二、无类型指针的定义。C中有void *类型,也就是可以指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型:Pointer。于是,
    ptr : Pointer;
    就与C中的
    void *ptr;
    等价了。三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),C 的语法是 (*ptr),Object Pascal则是 ptr^。四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,C 的语法是
    ptr = &Object;
    Object Pascal 则是
    ptr := @Object;
    也只是符号的差别而已。五、指针运算。在C中,可以对指针进行移动的运算,如:
    char a[20];
    char *ptr=a;
    ptr++;
    ptr+=2;
    当执行ptr++;时,编译器会产生让ptr前进sizeof(char)步长的代码,之后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两 个sizeof(char)大小的步长。同样,我们来看一下Object Pascal中如何实现:
    var
    a : array [1..20] of Char;
    ptr : PChar; //PChar 可以看作 ^Char
    begin
    ptr := @a;
    Inc(ptr); // 这句等价于 C 的 ptr++;
    Inc(ptr, 2); //这句等价于 C 的 ptr+=2;
    end;六、动态内存分配。C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码:
    int *ptr, *ptr2;
    int i;
    ptr = (int*) malloc(sizeof(int) * 20);
    ptr2 = ptr;
    for (i=0; i<20; i++){
    *ptr = i;
    ptr++;
    }
    free(ptr2);
    Object Pascal中,动态分配内存的函数是GetMem(),与之对应的释放函数为FreeMem()(传统Pascal中获取内存的函数是New()和 Dispose(),但New()只能获得对象的单个实体的内存大小,无法取得连续的存放多个对象的内存块)。因此,与上面那段C的代码等价的 Object Pascal的代码为:
    var ptr, ptr2 : ^integer;
    i : integer;
    begin
    GetMem(ptr, sizeof(integer) * 20); 
    //这句等价于C的 ptr = (int*) malloc(sizeof(int) * 20);
    ptr2 := ptr; //保留原始指针位置
    for i := 0 to 19 do
    begin
    ptr^ := i;
    Inc(ptr);
    end;
    FreeMem(ptr2);
    end;
    对于以上这个例子(无论是C版本的,还是Object Pascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成 20,那么就会出问题了(内存访问越界)。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同 样)。七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:
    char str[15];
    char *pstr;
    strcpy(str, "teststr");
    strcat(str, "_testok");
    pstr = (char*) malloc(sizeof(char) * 15);
    strcpy(pstr, str);
    printf(pstr);
    free(pstr);
    而在Object Pascal中,有了String类型,因此可以很方便的对字符串进行各种运算。但是,有时我们的Pascal代码需要与C的代码交互(比如:用 Object Pascal的代码调用C写的DLL或者用Object Pascal写的DLL准备允许用C写客户端的代码)的话,就不能使用String类型了,而必须使用两种语言通用的字符数组。其实,Object Pascal提供了完全相似C的一整套字符数组的运算函数,以上那段代码的Object Pascal版本是这样的:
    var str : array [1..15] of char;
    pstr : PChar; //Pchar 也就是 ^Char
    begin
    StrCopy(@str, 'teststr'); //在C中,数组的名称可以直接作为数组首地址指针来用
    //但Pascal不是这样的,因此 str前要加上取地址的运算符
    StrCat(@str, '_testok');
    GetMem(pstr, sizeof(char) * 15);
    StrCopy(pstr, @str);
    Write(pstr);
    FreeMem(pstr);
    end;八、函数指针。在动态调用DLL中的函数时,就会用到函数指针。假设用C写的一段代码如下:
    typedef int (*PVFN)(int); //定义函数指针类型
    int main()
    {
    HMODULE hModule = LoadLibrary("test.dll");
    PVFN pvfn = NULL;
    pvfn = (PVFN) GetProcAddress(hModule, "Function1");
    pvfn(2);
    FreeLibrary(hModule);
    }
    就我个人感觉来说,C语言中定义函数指针类型的typedef代码的语法有些晦涩,而同样的代码在Object Pascal中却非常易懂:
    type PVFN = Function (para : Integer) : Integer;
    var
    fn : PVFN; 
    //也可以直接在此处定义,如:fn : function (para:Integer):Integer;
    hm : HMODULE;
    begin
    hm := LoadLibrary('test.dll');
    fn := GetProcAddress(hm, 'Function1');
    fn(2);
    FreeLibrary(hm);
    end;delphi指针简单入门:   
        
      看一个指针用法的例子:   
      1         var   
      2             X,   Y:   Integer;       //   X   and   Y   整数类型   
      3             P:   ^Integer;           //   P   指向整数类型的指针   
      4         begin   
      5             X   :=17; //   给   X   赋值   
      6             P   :=   @X;                   //   把   x的地址赋给p   
      7             Y   :=   P^;                   //   取出p所指向的数值赋给y   
      8         end;   
        
      第二行定义了两个变量X,y.   第三行声明了p是指向整数类型的指针;意味着p能够指向x或者y的地址.第五行赋给x值,第六行把x的地址赋给p.最   
        
      后通过p指向的变量赋值给y.此时,x和y有相同的值.   
        
      操作符@用来取出变量的地址,也可以取出过程和函数的地址.   
        
      而符号^有两个目标,   
      当它出现在类型定义的前面时如 ^typename 表示指向这种类型的指针;   
      当它出现在指针变量后边时   如 point^ 返回指针指向的变量的值;   
        
      理解指针比较容易理解面向对象的pascal语言,因为指针经常在幕后操作.任何要求动态分配大的内存空间的类型可以用指针类型.例如   
        
      ,long-string变量,实际在使用指针进行操作.另外一些高级的编程技术需要使用指针类型.   
      有时指针是适应object   pascal严格的类型限制的唯一方法.同过一个通用的指针类型,通过类型转换成不同的指针类型,如下面的例子:   
      type   
        
          PInteger   =   ^Integer;   
      var   
          R:   Single;   
          I:   Integer;   
          P:   Pointer; //通用的指针   
          PI:   PInteger;   
      begin   
          P   :=   @R; //取出R的内存地址   
          PI   :=   PInteger(P); //把通用类型转换成指向整数类型的指针   
          I   :=   PI^;   
      end;   
        
      当然了,实数和整数的存储格式不同.这种赋值是把原始的二进制数据从R拷贝到I,而不进行转换.   
        
      保留字nil是一个特殊的常量可以赋给任何指针类型,当nil赋給一个指针时,指针什么也不指向,是一个空指针.   
        
      @操作符返回变量的内存中的存储地址,或者是过程\函数\方法;   
        
      1.如果变量,@X返回的是x的地址。如果编译选项{$T-}没有打开,着返回的事一个通用的指针,如果编译选项打开了,着返回的是x的类型对应的指   
        
      针.   
        
      2.如果是例程(过程\函数),@F返回的是F的入口点,@F的类型是一个指针。   
        
      3.当@用在类的方法中时,则方法的名称必须有类名,例如@TMyclass.Dosomething   
      指针指向TMyclass的dosomething方法。   
        
        
      当一个过程变量在赋值语句的左边时,编译器期望一个过程值在赋值语句的右边。这种赋值使得左边的变量可以指向右边定义的过程或者函数   
        
      入口点。换句话说,可以通过该变量来引用声明的过程或者函数,可以直接使用参数的引用。   
        
      var   
        
          F:   function(X:   Integer):   Integer;   
          I:   Integer;   
      function   SomeFunction(X:   Integer):   Integer;   
        ...   
      F   :=   SomeFunction;     //   给f赋值   
      I   :=   F(4);                     //   调用所指向的函数   
        
      在赋值语句中,左边变量的类型决定了右边的过程或者方法指针解释。   
        
      var   
        
          F,   G:   function:   Integer;   
          I:   Integer;   
      function   SomeFunction:   Integer;   
        ...   
      F   :=   SomeFunction;     //   给f赋值   
      G   :=   F;                           //   把F的值拷贝给G   
      I   :=   G;                           //   调用函数   
        
      第一句获得函数的入口,第二句将指针复制,第三句获得函数的返回值。   
        
      有时候还可以这样使用   
      if   F   =   MyFunction   then   ...;   
      在这里,F的出现导致一个函数调用;编译器调用F指向的函数,然后调用Myfunction,比较结果。这个规则是无论何时一个过程变量(   
        
      procedural   variable)出现在一个表达式中,它表示调用所指向的函数或者过程。有时F指向一个过程(没有返回值),或者f指向一个需要参   
        
      数的函数,则前面的语句会产生一个编译错误。要比较F和Myfunction需要用   
      if   @F   =   @MyFunction   then   ...;   
      @F把F转换成一个包含地址的无类型的指针变量,@myfunction返回myfunction的地址。   
      获得一个过程变量的内存地址使用@@。例如,@@F返回F的地址。   
        
      @操作符通常把一个无类型的指针值赋给一个过程变量,例如:   
      var   StrComp:   function(Str1,   Str2:   PChar):   Integer;   
        ...   
      @StrComp   :=   GetProcAddress(KernelHandle,   'lstrcmpi');   
      调用GetProcAddres函数,用strcomp指向这个值   
      任何过程变量可以赋成nil,表示指证什么也不指向。但是试图调用一个nil值的过程变量导致一个错误,为了测试一个过程变量是否可以赋值   
        
      ,用标准的赋值函数Assigned   
      if   Assigned(OnClick)   then   OnClick(X);   
        
      

  3.   

    liuin说的好啊………………
    的确是这样的…………
      

  4.   

    //in C++
    //CHAR *
    //in Delphi 
    //pchar就是^char;
    var
    i:integer; 
    s:pchar; 
    str:string;
    begin 
    i:=65; 
    s:=pchar(@i);//这一句相当于下面的两句; 
    //pchar(@i):@i是指取整数的地址,转换成一个字符指针,一个整型值实际上占用4个字节的空间.
    //这样进行转换,实际上你就把这4个字节的数据按字节转换成了字符了.
    按上面的转换,有如下结果:
    //如:i:=$41;//s:='A';
         i:=$3041;//s:='0A';
         i:=$413041;//s:='A0A';
         i:=$30413041//s:='0A0Ah?' 
    为什么最后会有乱码?
    因为pchar为字符指针,指向一个字符串是,结束符是#0,一个整型数据为4字节数据,不可能有第5个字节了.因此没有#0,
    故为乱码了......
    end; 
      

  5.   

    liuin说的好啊……………… 
    的确是这样的…………------------------------------学习了