Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar(来自http://delphi.cjcsoft.net/论坛)
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
Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar(来自http://delphi.cjcsoft.net/论坛)的更多相关文章
- Java中char和String 的深入理解 - 字符编码
开篇 https://blog.csdn.net/weixin_37703598/article/details/80679376 我们并不是在写代码,我们只是将自己的思想通过代码表达出来! 1 将思 ...
- java中去除字符串(String)中的换行字符(\r \n \t)
例1: public class Test { public static void main(String[] args) { String s = "'sds gdasda" ...
- 在java中除去字符串(String)中的换行字符(\r \n \t)
我们先来看几个例子: 例1: public class Test { public static void main(String[] args) { String s = "'sds gd ...
- C++ Tricks(一)—— 判断字符串 string 对象的所有字符都相等
S == string(S.size(), S[0]);
- java中除去字符串(String)中的换行字符(\r \n)
有时在文本框中输入内容特别是粘贴内容时会出现一些换行符(\r\n),如下,在做字数验证或保存到数据库中时应过滤掉. str.replaceAll("\r|\n","&qu ...
- Delphi调用WINAPI时到底应该是指针还是结构体(注意是Delphi变量本身就是指针)
看MSDN,GetWindowRect的说明如下: BOOL WINAPI GetWindowRect( _In_ HWND hWnd, _Out_ LPRECT lpRect // 注意,没* ...
- char*、string、CString各种字符串之间转换
参考博客: http://blog.csdn.net/luoweifu/article/details/20242307 http://blog.csdn.net/luoweifu/article/d ...
- Java String字符串/==和equals区别,str。toCharAt(),getBytes,indexOf过滤存在字符,trim()/String与StringBuffer多线程安全/StringBuilder单线程—— 14.0
课程概要 String 字符串 String字符串常用方法 StringBuffer StringBuilder String字符串: 1.实例化String对象 直接赋值 String str=& ...
- [ Java学习基础 ] String字符串的基本操作
字符串的拼接 String字符串虽然是不可变的字符串,但也同样可以进行拼接,只是会产生一个新的对象.String字符串拼接的时候可以使用"+"运算符或String的concat(S ...
随机推荐
- Lucene核心--构建Lucene搜索(上篇,理论篇)
2.1构建Lucene搜索 2.1.1 Lucene内容模型 一个文档(document)就是Lucene建立索引和搜索的原子单元,它由一个或者多个字段(field)组成,字段才是Lucene的真实内 ...
- 基于visual Studio2013解决C语言竞赛题之0802图书信息查询
题目 解决代码及点评 /* 功能:有一批图书,每本书有:书名(name),作者(author) , 编号(num),出版日期(date)四个数据, 希望输入后按书名的字母顺序将各书的记录排列好, ...
- HDU 4720Naive and Silly Muggles热身赛2 1005题(分锐角钝角三角形讨论)
Naive and Silly Muggles Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- Google - Pagerank
词条权值的局限. 上一篇blog以信息和概率的角度探讨了词条对于文档的权值. 见blog:http://blog.csdn.net/ice110956/article/details/17243071 ...
- Azure 云 Web 应用程序
Azure 云 Web 应用程序 原文:Getting Started作者:Rick Anderson翻译:谢炀(Kiler)校对:孟帅洋(书缘).刘怡(AlexLEWIS).何镇汐 设置开发环境 安 ...
- yw info
浙江省公开招聘聘任制公务员公告 浙江省公开招聘聘任制公务员公告-浙江组织工作网-浙江在线 浙江省公开招聘聘任制公务员公告
- 【虚拟化实战】容灾设计之一VR vs SRM
作者:范军 (Frank Fan) 新浪微博:@frankfan7 从本文开始,我们将介绍一系列的关于容灾的解决方案.先探讨应用的场景,然后再深入介绍技术架构. 情景一: 某小型公司的虚拟化环境中,在 ...
- CF 224 B Array
给你n个数,求[l, r] 的一段数,a[l] - a[r] 一共含有k个不相同的数,且sum a[l, r] 最小的那一段. 用队列维护当前数段中不同元素的个数即可. #include<ios ...
- KaOS 2016.04 发布,桌面 Linux 发行版
KaOS 2016.04 发布了,KaOS是一份桌面Linux发行,其特色在于最新版本的KDE桌面环境及其他流行的使用Qt工具包的软件程序.它最初基于Arch Linux,但从2013年四月起,开发者 ...
- Windows Azure入门教学系列 (四):使用Blob Storage
本文将会介绍如何使用Blob Storage.Blob Storage可以看做是云端的文件系统.与桌面操作系统上不同,我们是通过REST API来进行对文件的操作.有关REST API的详细信息,请参 ...