关于PChar和指针

来源:互联网 发布:上药控股 知乎 编辑:程序博客网 时间:2024/06/13 18:10

  对于刚开始学编程的人来说,指针无疑是最大的恐惧和进步障碍了. 我本人也是如此,居然毕业1年后还是见到^就怕的要命.其实现在想来,其实指针变不是什么难的东西,而且灵活运用它能有带来许多便利,很多人把指针比喻成门牌号码,这个比喻是再恰当不过了,一个门牌号码你当然看不到,这个门牌所对应的具体的是哪个房子哪栋楼是什么样的吧,指针也一样,在win32里它也只是一个占4个字节(32位)的数字,而这个数字对应的内存具体所保存的是什么东西,你不去访问它是不知道的.

  很多人在写要提供其他语言调用的dll的时候,知道要用pchar来做为字符串,我就以pchar来做一些简单的介绍吧.

首先我们来看一下pchar的定义:在随便哪个事件里定义一个P:PChar将鼠标放到PChar上,可以看到type System.PChar=^Char可以看到PChar就是一个指向Char类型的指针,另外PAnsiChar类型的也可以看到type System.PAnsiChar:PChar 所以你应该以后不会问PAnsiChar和PChar有什么不同了吧.

既然是指针,如果要使用就要给它分配内存,或者将它指向一个已经分配了的内存.我们先来看给PChar分配内存的函数,delphi提供了一个叫StrAlloc的函数来给null-terminated string类型的字符串分配内存,该函数可以用来给PChar分配size(参数)字节的内存,并将PChar指向第一个字符.知道它的作用,我们再来看下它的源代码(按住Ctrl点函数):

function StrAlloc(Size: Cardinal): PChar;
begin
  Inc(Size, SizeOf(Cardinal));
  GetMem(Result, Size);
  Cardinal(Pointer(Result)^) := Size;
  Inc(Result, SizeOf(Cardinal));
end;

一句来解释下,Inc(Size, SizeOf(Cardinal));将要分配的内存加上一个Cardinal的长度,为什么后面再说

GetMem(Result, Size);分配size长度的内存,并将Result指向这块内存开头,注意GetMem分配的都是堆内存.

Cardinal(Pointer(Result)^) := Size;将Result指向的内存的前4个字节填上Size的大小.

Inc(Result, SizeOf(Cardinal));将Result的指加4,也就是将Result往后指了4个字节
现在可以看出来了吧,StrAlloc分配内存时会用4个字节来保存函数申请的内存的大小.对应的释放的函数StrDispose函数这里就不说了.所以如果要得到一个PChar的申请的缓存的大小只要看这4个字节就知道了.其实只要取到这4个字节保存的数据-去4就是了,但其实delphi里提供了StrBufSize函数可以获取,方法就是这样的,大家可以注意到它另外申请了个PChar变量,大家可以自己想想如果不用这个变量的话程序该怎么改,还有函数的定义该怎么改.

来看这样一段程序:

var
  P:PChar;
  S:String;
begin
  S:='aaaa';
  try
    P:=StrAlloc(1024);
    //P:=StrPCopy(P,S);
    P:=PChar(S);
    Showmessage(P);
    Showmessage(InttoStr(Length(P)));
  finally
    StrDispose(P);
  end;
end;

以上代码运行会发现StrDispose(P);这句会报Invalid pointer operation,非法的指针操作,为什么呢?

因为P:=PChar(S);这句已经将P指向一个局部变量的内存,而它的分配和释放是由delphi编译器来管理的,你无法操作的,而你原来申请的1024个字节的内存已经泄露了.所以指针操作里千万不要再创建内存后又重新指向另外一个地方.前2天有个人问我,2个PChar的字符能不能连接直接用+来,也许你该想想,2个门牌号码的数字加起来是不是就是代表这2个房间呢? 

原创粉丝点击