一. PChar注意用例
1.1 小心PChar转化
大家看下面这个函数,会得到预期的结果,答案是也许偶尔你会得到你要的结果。但是,这样用是错误的!
function title(n: Integer): PChar;
var
s: string;
begin
s := Format('title - %d', [n]);
Result := PChar(s);
end;
因为在该函数调用结束后,String已经释放了。也许你要问,我试过了啊可以得到正确的结果啊! 所以上面说偶尔你会得到你要的结果,是因为string的引用
计数已经为0了,即内存标记为该string的区域是空闲的;但并没有对该区域进行初始化,所以如果以后的程序没用过该内存区域的话;你就侥幸得到了正确的返回
值!
1.2 PChar的分配空间
1.2.1 由于这样的例子很多,我在这里就举一个在类中运用PChar的例子:
TBidCell = class
private
FName: PChar;
procedure SetName(const Value: string);
function GetName: string;
public
constructor Create; reintroduce;
destructor Destroy; override;
property Name: string read GetName write SetName;
end;
由于私有变量FName是一个PChar类型,所以必须给它分配空间;我想大家已经想到了,要在SetName方法里分配合适的空间,就如:
constructor TBidCell.Create;
begin
GetMem(FName, 0); // 这里需要注意的是对 分配内存和释放内存 一定要成对的出现
end;
destructor TBidCell.Destroy;
begin
FreeMem(FName);
inherited;
end;
function TBidCell.GetName: string;
begin
Result := FName;
end;
procedure TBidCell.SetName(const Value: string);
begin
if FName = Value then Exit;
FreeMem(FName);
GetMem(FName, Sizeof(Value));
StrCopy(FName, PChar(Value));
end;
1.2.2 又如下一段代码:
1.2.2.1 例子:
TBidCell = class
private
FName: PChar;
public
constructor Create; reintroduce;
destructor Destroy; override;
property Name: string read GetName write SetName;
end;
constructor TBidCell.Create;
begin
end;
destructor TBidCell.Destroy;
begin
FreeMem(FName);
inherited;
end;
当程序调用TBidCell.Create后,再直接调用Free;程序是不会报错的,因为类创建时已经将所有变量初始化了;所以再Destroy中调用FreeMem(FName)而不会
出错。但是,推荐 分配和释放内存 要成对出现。
1.2.2.2 又如例子
procedure TForm1.Button1Click(Sender: TObject);
var
s: PChar;
begin
FreeMem(s);
end;
这段代码在Debug编译环境运行下,是不会报任何错误的;但是,当编译前选择优化编译时,就会释放报错!!
二. PChar、String、ShortString、AnsiString、WideString的区别
2.1 shortstring:
与传统的Pascal字符串相对应,存储格式为压缩格式,字符个数有限,最大
为255个
2.2 ansistring(string缺省编译状态下):
存储格式为压缩格式,一个字符串的个数和大(最大长度可以到2GB)。字符串中的字符也基于标准的ANSIChar字符类型WideString:与AnsiString类似,不
过是基于WideChar字符类型(UniCode字符集),用了存储Unicode字符。引入这种类型,主要是为了支持OLE编程
2.3 至于string和PChar的区别就多了
string和Char数组都是一块内存, 其中存放连续的字符. string保存具体字符的内存对用户是透明的, 由Delphi管理它的分配, 复制和释放, 用户不能干预
(其实也可以, 不过是通过非法途径). Char数组就不必说了吧?
PChar是一个指针, 它的大小只有32位. 定义时由Delphi自动填0. 要将PChar作为字符串使用的话必须自己分配内存用完必须自己释放. PChar型字符串由#0表
示字符串结尾Delphi所提供的相关PChar字符串的操作都是判断#0来决定字符串的结尾的。因为PChar是指针,所以它能指向任何地方(也就是说它不一定非要指向字
符串不可).把一个String赋值给PChar只是将String中保存具体字符串的内存的地址给PChar变量. 当然也可以把Char数组第一个元素的地址给PChar.至于 哪个占
用内存小, Char数组<PChar(指分配过字符串的)<string(除了具体字符串外还 包含字符串长度)如果空字符串那么PChar<String<array [0..n] of Char
从速度来说毫无疑问string最慢, 例如:作为参数传递(非var调用时)给过程时string将整个字串的副本传递过去, PChar将指针本身的副本传递过去(32位), Char
数组和PChar一样, 传递的是第一个元素的地址副本.不过就灵活性来说string最高, 而且Delphi支持的函数最多. 另外可以将String作为Buffer使用(因为它当中
可以包含字符0).