Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar(来自http://delphi.cjcsoft.net/论坛)

   2023-02-09 学习力0
核心提示:Delphi有三种类型的字符:AnsiChar这是标准的1字节的ANSI字符,程序员都对它比较熟悉。WideChar这是2字节的Unicode字符。Char在目前相当于AnsiChar,但在Delphi 2010 以后版本中相当于WideChar.记住因为一个字符在长度上并不表示一个字节,所以不能在应用程序

Delphi有三种类型的字符:

AnsiChar这是标准的1字节的ANSI字符,程序员都对它比较熟悉。

WideChar这是2字节的Unicode字符。

Char在目前相当于AnsiChar,但在Delphi 2010 以后版本中相当于WideChar.

记住因为一个字符在长度上并不表示一个字节,所以不能在应用程序中对字符长度进行硬编码,

而应该使用Sizeof()函数。注意Sizeof()标准函数返回类型或实例的字节长度。

Delphi有下列几种不同的字符串类型 String:

ShortString保留该类型是为了向后兼容 Delphi1.0,它的长度限制在255个字符内。 
ShortString[0] = len : $H- 代表 ShortString

AnsiString是Pascal缺省的字符串类型,它由AnsiChar字符组成,其长度没有限制,
同时与null结束的字符串相兼容。<Delphi2.0开始引入> : $H+ 代表 AnsiString

WideString功能上类似于AnsiString,但它是由WideChar字符组成的。

WideString没有引用计数,所以将一个WideString字符串赋值给另一个WideString字符串时,
就需要从内存中的一个位置复制到另一个位置。这使得WideString在速度和内存的利用上不如AnsiString有效。

缺省情况下,编译器认为是AnsiString字符串< <Delphi2010 String 默认为 WideString>

Delphi有下列几种不同的字符串指针类型:

PChar指向null结束的Char字符串的指针,类似于C的char*或lpstr类型。

PAnsiChar指向null结束的AnsiChar字符串的指针。

PWideChar指向null结束的WideChar字符串的指针。<Delphi2010 PChar 默认为 PWideChar>

字符数组

静态字符数组 CharArray : array[0..Length-1] of Char;

动态字符数组 CharArray : array of Char;

动态数组的构造和静态数组完全不同, 它和 String 的构造相似

String  : RefCount : Length : Char Char .... 0x00 < Delphi >

DynArry : RefCount : Length : Char Char .... 0x00 < Programmer >

StaArry :                   : Char Char .... 0x00 < Programmer >

 

                           : PChar = PChar( String ) = PChar( DynArray ) = PChar( StaArray )

StrLen( PChar )  : 字符个数, StrLen( PChar ) * SizeOf( Char ) : 字节个数 ( WideChar = 2 )

Length( String ) : 字符个数, Length( PChar ) * SizeOf( Char ) : 字节个数 ( AnsiChar = 1 )

 

1.AnsiString类型

AnsiString(或长字符串)类型是在Delphi2.0开始引入的,因为Delphi1.0的用户特别需要一个容易使用而且没有255个字符限制的字符串类型,而AnsiString正好能满足这些要求。


虽然AnsiString在外表上跟以前的字符串类型几乎相同,但它是动态分配的并有自动回收功能,正是因为这个功能AnsiString有时被称为生存期自管理类型。ObjectPascal能根据需要为字符串分配空间,所以不用像在C/C++中所担心的为中间结果分配缓冲区。另外,AnsiString字符串总是以null字符结束的,这使得AnsiString字符串能与Win32API中的字符串兼容。实际上,AnsiString类型是一个指向在堆栈中的字符串结构的指针。


AnsiString字符串类型有引用计数的功能,这表示几个字符串都能指向相同的物理地址。因此,复制字符串因为仅仅是复制了指针而不是复制实际的字符串而变得非常快。当两个或更多的AnsiString类型共享一个指向相同物理地址的引用时,Delphi内存管理使用了copy-on-write技术,一个字符串要等到修改结束,才释放一个引用并分配一个物理字符串。下面的例子显示了这些概念:


var

S1,S2:string;

begin

//给S1赋值,S1的引用计数为1

S1:='Andnowforsomething...';

S2:=S1;//现在S2与S1指向同一个字符串,S1的引用计数为2

//S2现在改变了,所以它被复制到自己的物理空间,并且S1的引用计数减1

S2:=S2+'completelydifferent1';

end;


Win32的兼容

正如前面所提到,AnsiString字符串总是null结束的。因此,它能跟以null结尾的字符串兼容,这就使得调用Win32API函数或其他需要PChar型字符串的函数变得容易了。只要把一个字符类型强制转换为PChar类型(在2.8节“强制类型转换和类型约定”中将介绍强制类型转换)。下面的代码演示了怎样调用Win32的GetWindowsDirectory()函数,这个函数需要一个PChar类型的参数:

var

S:String;

begin

SetLength(S,256);//重要!首先给字符串分配空间

//调用API函数,S现在包含目录字符串

GetWindowsDirectory(PChar(S),256);

如果使用了将AnsiString字符串强制转换为PChar类型的函数和过程,在使用结束后,要手工把它的长度恢复为原来以null结束的长度。STRUTILS单元中的RealizeLenght()函数可以实现这一点:

procedureRealizeLength(varS:string);

begin

SetLength(S,StrLen(PChar(S)));

end;

调用ReallizeLength():

var

S:string;

begin

SetLength(S,256);//重要!首先给字符串分配空间

//调用函数,S现在包含目录字符串

GetWindowDirectory(PChar(S),256);

RealizeLength(S);//设置S的长度为null结束的长度

end;


跟AnsiString类型字符串不一样,ShortString跟以null结尾的字符串不兼容,正因为这样,用ShortString调用Win32函数时,要做一些工作。下面这个ShortStringAsPChar()函数是在STRUTILS.PAS单元中定义的。


funcfunctionShortStringAsPChar(varS:ShortString):PChar;


{这函数能使一个字符串以null结尾,这样就能传递给需要PChar类型参数的Win32API函数,如果字符串超过254个字符,多出的部分将被截掉}

begin

ifLength(S)=High(S)thenDec(S[0]);{如果S太长,就截取一部分}

S[Ord(Length(S))+1]:=#0;{把null加到字符串的最后}

Result:=@S[1];{返回PChar化的字符串}

end;

Win32API函数需要以null结尾的字符串,不要把ShortString字符串传递给API函数,因为编译器将报错,长字符串可以传递给Win32API函数。


WideString类型

WideString类型像AnsiString一样是生存期自管理类型,它们都能动态分配、自动回收并且彼此能相互兼容,不过WideString和AnsiString的不同主要在三个方面:

WideString由WideChar字符组成,而不是由AnsiChar字符组成的,它们跟Unicode字符串兼容。

WideString用SysAllocStrLen()API函数进行分配,它们跟OLE的BSTR字符串相兼容。

WideString没有引用计数,所以将一个WideString字符串赋值给另一个WideString字符串时,就需要从内存中的一个位置复制到另一个位置。这使得WideString在速度和内存的利用上不如AnsiString有效。


就像上面所提到的,编译器自动在AnsiString类型和WideString类型的变量间进行转换。示例如下:

var

W:wideString;

S:string;

begin

W:='Margaritaville';

S:=W;//wideString转换成AnsiString

S:='ComeMonday';

W:=S;//AnsiString转换成WideString

end;

为了能灵活地运用WideString类型,ObjectPascal重载了Concat()、Copy、Insert()、Length()、Pos()和SetLength()等例程以及+、=和<>等运算符。


就像AnsiString和ShortString类型一样,能用数组的下标来访问WideString中一个特定的字符:

var

W:WideString;

C:WideChar;

begin

W:='EbonyandIvorylivinginprefectharmony';

C:=W[Length(W)];//C包含W字符串的最后一个字符

end;

以null结束的字符串

正如前面所提到的,Delphi有三种不同的以null结束的字符串类型:PChar、PAnsiChar和PWideChar。它们都是由Delphi的三种不同字符组成的。这三种类型在总体上跟PChar是一致的。PChar之所以保留是为了跟Delphi1.0和Win32API兼容,而它们需要使用以null结束的字符串,PChar被定义成一个指向以null(零)结束的字符串指针与AnsiString和WideString类型不同,PChar的内存不是由ObjectPascal自动产生和管理的,要用Object Pascal的内存管理函数来为PChar所指向的内存进行分配。PChar字符串的理论最大长度是4GB


在大多数情况下,AnsiString类型能被用成PChar,应该尽可能地使用AnsiString,因为它对字符串内存的管理是自动,极大地减少了应用程序中内存混乱的错误代码,因此,要尽可能地避免用PChar类型以及对它相应进行人工分配内存。


正如在前面所提到的,PChar变量需要人工分配和释放存放字符串的内存。通常,用StrAlloc()函数为PChar缓冲区分配内存,但是其他几种函数也能用来为PChar类型分配函数,包括AllocMem()、GetMem()、StrNew()和VirtualAlloc()API函数。这些函数有相应的释放内存的函数。


--------------------------------------------------------------------------------


//单字符 Char、AnsiChar (在目前版本(2007)中, 它们是一回事, 只有 1 字节大小)
var
c: Char; {Char 类型的取值范围是: #0..#255, 用十六进制表示是: #$0..#$FF}
begin
{用十进制方式赋值:}
c := #65;
ShowMessage(c); {A}

{用十六进制方式赋值:}
c := #$41;
ShowMessage(c); {A}

{用 Chr 函数代替 # 符号}
c := Chr(65);
ShowMessage(c); {A}
c := Chr($41);
ShowMessage(c); {A}

{Char 长度当然会是 1}
ShowMessage(IntToStr(Length(c))); {1}

{Char、AnsiChar 允许这样方便地赋值(也就是和 1 字节长度的字符串是兼容的):}
c := 'B';
ShowMessage(c); {B}
end;
--------------------------------------------------------------------------------

//UniCode 字符 WideChar; 和 AnsiChar 不同, WideChar 是占 2 字节大小.
var
c: WideChar; {WideChar 的取值范围是: #0..#65535, 用十六进制表示是: #$0..#$FFFF}
begin
{WideChar 兼容了 AnsiChar 的 #0..#255; 但占用了 2 字节大小}
c := #65;
ShowMessage(c); {A}
ShowMessage(IntToStr(Length(c))); {1; 这是字符长度}
ShowMessage(IntToStr(SizeOf(c))); {2; 但占用 2 个字节}

{用十六进制赋值}
c := #$4E07;
ShowMessage(c); {万}
ShowMessage(IntToStr(Length(c))); {1; 这是字符长度}
ShowMessage(IntToStr(SizeOf(c))); {2; 但占用 2 个字节}

{用十进制赋值}
c := #19975;
ShowMessage(c); {万}

{如果不超出 #255 的范围是可以直接赋值的}
c := 'B';
ShowMessage(c); {万}

{这样不行}
//c := '万'; {这是 Delphi 的支持问题, 估计 Delphi 2008 应该可以解决}

{可以这样变通一下:}
c := WideString('万')[1];
ShowMessage(c); {万}

{用 WideChar 的方式显示我的名字}
ShowMessage(#19975#19968);    {万一}
ShowMessage(#19975 + #19968); {万一}
ShowMessage(#$4e07#$4e00);    {万一}
end;
--------------------------------------------------------------------------------

//字符指针 PChar、PAnsiChar; 在当前版本(2007)中它们没有区别.
var
p: PChar;
str: string;
begin
{可以给 PChar 直接赋予字符串常量}
p := '万一';
ShowMessage(p);                   {万一}
ShowMessage(IntToStr(Length(p))); {4}

{给变量值需要转换}
str := '万一的 Delphi 博客';
p := PChar(str); {转换}
ShowMessage(p);                   {万一的 Delphi 博客}
ShowMessage(IntToStr(Length(p))); {18}
end;
--------------------------------------------------------------------------------

//宽字符指针 PWideChar
var
p: PWideChar;
str: WideString; {注意这里不是 String}
begin
{可以给 PWideChar 直接赋予字符串常量}
p := '万一';
ShowMessage(p);                   {万一}
ShowMessage(IntToStr(Length(p))); {2}

{给变量值需要转换}
str := '万一的 Delphi 博客';
p := PWideChar(str); {转换}
ShowMessage(p);                   {万一的 Delphi 博客}
ShowMessage(IntToStr(Length(p))); {13}
end;

详见:http://www.haogongju.net/art/1213487

        http://www.haogongju.net/art/1529020

        http://www.haogongju.net/art/1994071 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Delphi中的消息处理机制 delphi 方法
    每一个VCL都有一内在的消息处理机制,其基本点就是构件类接收到某些消息并把它们发送给适当的处理方法,如果没有特定的处理方法,则调用缺省的消息处理句柄。    其中mainwndproc是定义在Twincontrol类中的一个静态方法,不能被重载(Override)。它不直接处
    02-09
  • Delphi XE6 通过JavaScript API调用百度地图
    Delphi XE6 通过JavaScript API调用百度地图
    参考昨天的内容,有朋友还是问如何调用百度地图,也是,谁让咱都在国内呢,没办法,你懂的。 首先去申请个Key,然后看一下百度JavaScript的第一个例子:http://developer.baidu.com/map/jsdemo.htm下一步,就是把例子中的代码,移动TWebBrower中。 unit Unit
    02-09
  • Delphi编译/链接过程 delphi编程案例
    Delphi编译/链接过程 delphi编程案例
    下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件。当Delphi编译项目(Project)时,将编译项目源文件、窗体单元和其他相关单元,在这个过程中将会发生好几件事情:首先,Object Pascal编译器把项目单元编译为二进制对象文件,然后
    02-09
  • Delphi CompilerVersion Constant / Compiler C
    http://delphi.wikia.com/wiki/CompilerVersion_Constant The CompilerVersion constant identifies the internal version number of the Delphi compiler.It is defined in the System unit and may be referenced either in code just as any other consta
    02-09
  • Delphi revelations #1 – kbmMW Smart client
    Delphi 启示 #1 – kbmMW Smart client on NextGen (Android) – 作用域问题以更高级的方式使用kbmMW smart client,在Android设备上,我遇到了问题。通过继承TInvokeableVariantType,kbmMW smart client可以使用Delphi支持的特殊类型的自定义Variant,从而可
    02-09
  • Delphi 调用DLL外部函数时的指针参数
    某项目需要调用设备厂家提供的DLL的函数,厂家给了一个VB的例子,有个参数是ByRef pBuffer As Single。于是在Delphi中用buffer:array of single代替:function func(buffer:array of single;count:integer):integer;far;stdcall;external 'func.dll';调用后bu
    02-09
  • 《zw版·Halcon-delphi系列原创教程》 Halcon分
    《zw版·Halcon-delphi系列原创教程》 Halcon分类函数012,polygon,多边形为方便阅读,在不影响说明的前提下,笔者对函数进行了简化::: 用符号“**”,替换:“procedure”:: 用大写字母“X”,替换:“IHUntypedObjectX”:: 省略了字符:“const”、“OleVa
    02-09
  • 最简单的delphi启动画面(转)
    首先做一窗体,然后将BorderStyle的属性设为bsnone,放image控件,align设为alclient 然后将主程序的修改为 uses Windows, Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$ R *.res} begin Application.Initialize; Form2:=TForm2.Cre
    02-09
  • Delphi备忘三:TCollection的使用,用Stream保
     代码unit ufrmGetFunctionDefine;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,TypInfo,  Dialogs,ufrmStockBaseCalc, StdCtrls, ComCtrls,uQEFuncManager,uWnDataSet,uDataService;type  T
    02-09
  • Delphi Dcp 和BPL的解释
    dcp = delphi compiled package,是 package 编译时跟 bpl 一起产生出来的,记录着 package 中公开的 class、procedure、function、variable、const.... 等等的名称和相对位址。package英文翻译过来就是“包”。如果 某个控件包 A 引用了 控件包 B,当 控件包
    02-09
点击排行