(转)Delphi 中的字符串

一、Delphi 2009 之前的字符串(不支持 Unicode):

  Delphi 2009 之前的字符串分为 3 种:ShortString、AnsiString、WideString。

【ShortString】

  ShortString 是一种比较古老的 Pascal 字符串格式,它最多只能容纳 255 个字节的字符。当我们声明一个 ShortString 类型的变量时,Delphi 会自动申请 256 个字节的内存空间给该变量,其中第一个字节用来存放字符串的长度,后面的 255 个字节用来存放字符串内容,如果字符串的长度不够 255 个字节,则有多少字符就用多少内存,后面未用到的内存清零。

var
  SStr: ShortString;

  上面的声明就使 SStr 拥有了 256 个字节的内存空间:

Sizeof(SStr); { = 256; }

  直到 SStr 不再被使用时,Delphi 会自动释放 SStr 所占用的内存空间。

  我们还可以用下面的方式来声明 ShortString 类型的变量:

var
  SStr: string[16];

  这样,我们就声明了一个只能容纳 16 个字节内容的 ShortString 字符串,加上一个字节用来存放字符串的长度,SStr 一共占用 17 个字节的内存空间:

Sizeof(SStr); { = 17; }

  我们可以像使用字节数组(array of byte)那样来使用 ShortString,比如我们可以用下标来访问 ShortString 中的各个字符,可以用 High 和 Low 函数来获取 ShortString 的上限位置和下限位置。由于字符串的第一个字节存放的是字符串的长度,所以 SStr[0] 存放的是字符串的长度,例如:

var
  SStr: string[16];
begin
  SStr := ‘ABC‘;
{ 此时:
  Ord(SStr[0]);  // = 3   字符串长度为 3
  SStr[1];       // = ‘A‘ 第一个字符为 A
  SStr[2];       // = ‘B‘ 第二个字符为 B
  SStr[3];       // = ‘C‘ 第三个字符为 C
  SStr[4];       // = #0  其余位置清零 #0
  ……           //       其余位置清零 #0
  SStr[255];     // = #0  其余位置清零 #0
  High(SStr);    // = 16  上限位置为 16
  Low(SStr);     // = 0   下限位置为 0 }
end;

  接下来,我们来看看 SStr 的指针情况。

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  SStr: ShortString;

pS: Pointer;
  pS1: Pointer;
begin
  SStr := ‘ABC‘;

pS := Addr(SStr);        { 字符串变量 SStr 的地址 }
  pS1 := Addr(SStr[0]);    { 字符串的首地址 }

Memo1.Clear;
  Memo1.Lines.Add(IntToStr(Integer(pS)));  { 在我的电脑中显示为:1242240 }
  Memo1.Lines.Add(IntToStr(Integer(pS1))); { 在我的电脑中显示为:1242240 }
end;

----------

  上面的代码说明变量 SStr 的地址就是“存放字符串的内存块”的地址。这和后面讲到的 AnsiString 和 WideString 不同。

【AnsiString】

  AnsiString 是一种动态分配内存的字符串,也就是说当我们声明一个 AnsiString 时,它并不占用内存空间,比如:

var
  AStr: AnsiString;

  此时字符串的长度为 0,不占用内存空间:

Length(AStr);  { = 0 }

  这里为什么不用 Sizeof(AStr); 而用 Length(AStr); 因为 AStr 和 ShortString 不同,变量 AStr 的地址并不是“存放字符串的内存块”的地址,变量 AStr 中存放的只是一个指针,指向“存放字符串的内存块”,我们通过变量 AStr 可以找到“存放字符串的内存块”,请看下面的代码:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr: AnsiString;

pA: Pointer;
  pA1: Pointer;
begin
  AStr := ‘ABC‘;

pA := Addr(AStr);       { 字符串变量 AStr 的地址 }
  pA1 := Addr(AStr[1]);   { “存放字符串的内存块”的地址。Delphi 不允许访问 AStr[0] }

Memo1.Clear;
  Memo1.Lines.Add(IntToStr(Integer(pA)));  { 在我的电脑中显示为:1242504 }
  Memo1.Lines.Add(IntToStr(Integer(pA1))); { 在我的电脑中显示为:17539780 }
end;

----------

  从上面的代码中可以看出,字符串变量 AStr 的地址和“存放字符串的内存块”的地址是不一样的。所以用 Sizeof(AStr) 无法获取字符串的大小,只能获取一个指针的大小,永远为 Sizeof(Pointer);

  刚才说了,AnsiString 变量在刚声明的时候是不分配内存的,所以就不能使用 AStr[1],因为 AStr[1] 是指“被分配的内存块”中的第一个字符,而“内存块”根本就没有分配,哪来的第一个字符?所以在使用 AStr[1] 之前首先要判断 Length(AStr) 是否为 0,若为 0,就表示内存块未分配,就不能使用 AStr[1]。

  那什么时候 AStr 才分配内存呢?当我们给 AStr 赋值的时候,Delphi 就给 AStr 分配内存,例如:

----------
var
  AStr: AnsiString;     { 此时 AStr 未分配内存 }
begin
  AStr := ‘ABC‘;        { 此时 Delphi 给 AStr 分配了三个字节的内存用来存放 ‘ABC‘ }
  ShowMessage(AStr[1]); { 这时就可以使用 AStr[1] 了 }
  AStr := ‘ABCDEF‘;     { 此时 Delphi 增大字符串的内存空间来存放更多字符 }
  AStr := ‘‘;           { 此时 AStr 将刚分配的内存全部释放 }
  ShowMessage(AStr[1]); { 错误,因为此时未分配内存,所以不可以使用 AStr[1] }
end;

----------

  那么变量 AStr 和“存放字符串的内存块”之间是什么关系呢?变量 AStr 中存放的其实是一个指针,指向“存放字符串的内存块”。通过下面的代码可以很好的理解这个问题:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr: AnsiString;

pA: Pointer;      { 变量 AStr 的地址 }
  pA1: Pointer;     { 字符串中第一个字符的地址(即:内存块的地址) }
  pAP: Pointer;     { 变量 AStr 中所存放的指针 }
begin
  AStr := ‘ABC‘;    { 申请三个字节的内存块用来存放 ‘ABC‘ }

pA  := Addr(AStr);    { 获取变量 AStr 的地址 }
  pA1 := Addr(AStr[1]); { 获取内存块的地址 }
  pAP := Pointer(AStr); { 获取变量 AStr 中所存放的指针 }

Memo1.Clear;
  Memo1.Lines.Add(IntToStr(Integer(pA)));   { 变量 AStr 的地址 }
  Memo1.Lines.Add(IntToStr(Integer(pA1)));  { 内存块的地址 }
  Memo1.Lines.Add(IntToStr(Integer(pAP)));  { 变量 AStr 中所存放的指针 }
end;

----------

{ 运行结果 }
1242504      { 变量 AStr 的地址 }
17539780     { 内存块的地址 }
17539780     { 变量 AStr 中所存放的指针 }

----------

  由此可见 AStr 中存放的只是一个指针,指向“存放字符串的内存块”,我们可以通过 Pointer(AStr) 来得到这个内存块的地址。

  上面的代码有一个奇怪的地方,就是将 pA1 := Addr(AStr[1]); 和 pAP := Pointer(AStr); 两行代码的前后位置对调一下,运行结果就不同了(测试环境:Delphi XE2),下面是对调以后的运行结果:

----------

{ 对调以后的运行结果 }
1242504      { 变量 AStr 的地址 }
17539780     { 内存块的地址 }
5327792      { 变量 AStr 中所存放的指针 }

----------

  这或许是 Delphi 对字符串优化所造成的结果(Delphi 的 copy-on-write 技术),当我们仅仅是读取该字符串时,它的地址就是刚赋初始值时的地址(5327792),而当我们要修改字符串时( pA1 := Addr(AStr[1]) 也被认为是用户将要通过指针修改字符串),Delphi 就会把该字符串复制到新的地方(17539780)给用户修改并继续使用。如果“旧地址中的字符串”还同时被其它变量引用,比如 AStr := ‘ABC‘ 之后又 AStr2 := AStr,则保留旧地址,供 AStr2 继续使用,如果旧地址不再被其它变量使用,则将旧地址中的字符串全部释放。 )

  为了检验以上说法,我们用下面的代码再测试一次,这次,我们将 AnsiString 定义为常量,不允许修改,看看结果如何:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
const
  AStr: AnsiString = ‘ABC‘;
var
  pA: Pointer;      { 变量 AStr 的地址 }
  pA1: Pointer;     { 字符串中第一个字符的地址(即:内存块的首地址) }
  pAP: Pointer;     { AStr 中所存放的指针 }
begin
  pA  := Addr(AStr);    { 获取变量 AStr 的地址 }
  pAP := Pointer(AStr); { 获取变量 AStr 中所存放的指针(放前面) }
  pA1 := Addr(AStr[1]); { 获取内存块的地址(放后面) }

Memo1.Clear;
  Memo1.Lines.Add(IntToStr(Integer(pA)));   { 变量 AStr 的地址 }
  Memo1.Lines.Add(IntToStr(Integer(pA1)));  { 内存块的地址 }
  Memo1.Lines.Add(IntToStr(Integer(pAP)));  { 变量 AStr 中所存放的指针 }
end;

----------

{ 此时的运行结果 }

5379472      { 变量 AStr 的地址 }
5327460      { 内存块的地址 }
5327460      { 变量 AStr 中所存放的指针 }

----------

  字符串的地址没有发生变化,这验证了刚才我们说的 Delphi 的 copy-on-write 技术。这也解释了为什么提倡大家在不修改字符串内容的情况下,尽量将字符串声明为常量(比如函数的字符串参数),因为常量不会触发 Delphi 的 copy-on-write 技术,增加代码的执行效率。

  接下来有必要对 Length 函数做一下说明,Length 函数对于 ShortString 和 AnsiString 来说,都是指“字符串中的字节数(而不是字符数)”,请看下面的例子:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  SStr: ShortString;
  AStr: AnsiString;
begin
  Memo1.Clear;

SStr := ‘123你好吗‘;  { 一共 6 个字符 }
  AStr := ‘123你好吗‘;  { 一共 6 个字符 }

Memo1.Lines.Add(IntToStr(Length(SStr)));    { 结果 9 }
  Memo1.Lines.Add(IntToStr(Length(AStr)));    { 结果 9 }
end;

----------

  因为一个英文字符只占用 1 个字节的内存空间,而一个汉字要占用 2 个字节的内存空间,所以 SStr 和 AStr 都用了 9 个字节的内存空间来存放字符串。如果此时你使用 AStr[4] 来获取汉字“你”,那么只能获取半个汉字,此时的 AStr[4] 是 AnsiChar 类型(单字节)。所以用 AnsiString 处理汉字是很麻烦的,我们一般用 WideString 来处理带有汉字的字符串。

  关于 Delphi 不允许访问 AStr[0],其实 AnsiString 和 ShortString 有着类似的结构,也就是说在 AnsiString 字符串的前面也有一个数据区用来保存 AnsiString 的长度(字节数),这个数据区就是字符串之前的 4 个字节,我们可以通过指针来访问这个区域,而再之前的 4 个字节中还存放着字符串的引用计数,标识着这个字符串被几个字符串变量所引用。在 Delphi 7 的 system 单元中可以找到字符串结构的定义:

StrRec = packed record
  refCnt: Longint;   { 引用计数 }
  length: Longint;   { 字符串长度 }
end;

请看下面的代码:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr: AnsiString;
  P: PCardinal;    { Sizeof(Cardinal) = 4 字节 }
begin
  Memo1.Clear;

SetLength(AStr, 65530);
  P := PCardinal(AStr);

Dec(P); { 向前移动 4 个字节 }
  Memo1.Lines.Add(IntToStr(P^));    { 结果 65530   字符串长度 }
  Dec(P); { 再向前移动 4 个字节 }
  Memo1.Lines.Add(IntToStr(P^));    { 结果 1       引用计数 }
end;

----------

  从上面的结果可以看出,字符串的长度为 65530,引用计数为 1。

  关于 AnsiString 中可以存放的内容,有人说 AnsiString 中存放的是以 #0 结尾的字符串,和 C 语言的字符串类似,这样理解不准确,因为 AnsiString 中可以存放多个 #0 字符,#0 并不一定代表字符串的结尾。例如:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr, AStr2: AnsiString;
  I: Integer;
begin
  Memo1.Clear;

SetLength(AStr, 10);  { 在 AStr 中存放 10 个 #0 字符 }
  for I := 1 to 10 do
    AStr[I] := #0;

AStr2 := AStr;        { 看看赋值的过程中会不会发生字符丢失 }
  AStr2[5] := ‘A‘;
  Memo1.Lines.Add(IntToStr(Length(AStr2)));    { 结果 10,没有丢失字符 }
end;

----------

  也就是说 AnsiString 可以直接当内存来使用,它不只可以存放字符,而是可以存放任何东西,你甚至可以将一个图片的数据存入 AnsiString 的内存块中。用 AnsiString 代替内存使用有一个好处,就是 Delpih 会帮你管理这个内存,在你不需要使用该内存块的时候,Delphi 会自动帮你释放。

  但是这样的字符串不能和 PAnsiChar 类型一起使用,因为 PAnsiChar 才是真正的以 #0 结尾的字符串(我们刚才不是说了 AnsiString 其实就是一个指针吗,PAnsiChar 也是一个指针,在用法上和 AnsiString 有很多相同的地方),当你把上面的字符串赋值给一个 PAnsiChar 变量时,PAnsiChar 只会读取第一个 #0 之前的内容,而把第一个 #0 之后的所有内容都丢弃掉。请看下面的代码:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr: AnsiString;
  pAStr: PAnsiChar;
  I: Integer;
begin
  Memo1.Clear;

SetLength(AStr, 10);
  for I := 1 to 10 do
    AStr[I] := #0;

pAStr := ‘ABC‘;
  Memo1.Lines.Add(IntToStr(Length(pAStr)));    { 结果 3 }

pAStr := PAnsiChar(AStr);
  Memo1.Lines.Add(IntToStr(Length(pAStr)));    { 结果 0 }

pAStr := #0#0#0;
  Memo1.Lines.Add(IntToStr(Length(pAStr)));    { 结果 0 }
end;

----------

  好了,总结一下 AnsiString:

  AnsiString 变量只是一个指针,指向一个内存块,这个内存块用来存放实际的字符串。AnsiString 所指向的内存是动态分配的,如果 AnsiString 中未存放任何字符串,则 AnsiString 指向 nil。

  虽然 AnsiString 变量并不是真正的内存块,只是一个指针,但是我们仍然可以通过下标的方式来访问内存块中的字符。下标必须从 1 开始,Delphi 不允许 AnsiString 和 WideString 使用下标 0。

  我们可以通过如下方式访问到 AStr 所指向的内存块地址:

@AStr[1]
Pointer(AStr)

  我们可以通过如下方式访问到 AStr 所指向的内存块中的第一个字符、第二个字符、第三个字符:

AStr[1]、AStr[2]、AStr[3]
PAnsiChar(AStr)^ 、(PAnsiChar(AStr)+1)^ 、(PAnsiChar(AStr)+2)^

  PAnsiChar 类型和 AnsiString 类型之间可以很容易的相互转换。不过编译器在编译的时候会给出警告(不是错误)。例如:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  AStr: AnsiString;
  pAStr: PAnsiChar;
begin
  Memo1.Clear;

AStr := ‘ABC‘;
  pAStr := PAnsiChar(AStr);
  Memo1.Lines.Add(AStr);
  Memo1.Lines.Add(pAStr);

Memo1.Lines.Add(‘‘);

pAStr := ‘123‘;

AStr := pAStr;
  Memo1.Lines.Add(AStr);
  Memo1.Lines.Add(pAStr);
end;

----------

  关于 Length 函数,Length 函数对于 ShortString 和 AnsiString 来说返回的是它们所存放的字符串的字节数,而不是字符数。

  在 AnsiString 的字符串之前的 4 个字节中存放着字符串的总长度(总字节数),再之前的 4 个字节中存放着字符串的引用计数。

  AStr[n] 只能返回半个汉字,所以用 AnsiString 处理汉字是很麻烦的,我们一般用 WideString 来处理带有汉字的字符串。

  Delphi 对 AnsiString 和 WideString 都使用了 copy-on-write 技术,所以当我们不准备修改字符串的内容时,最好将字符串声明为常量,以提高程序的执行效率。

  Delphi 中的 AnsiString 可以直接当做内存来使用,如果你愿意这么用的话,Delphi 会帮你管理这块内存。申请内存很方便,直接 SetLength 就可以了。用完了 Delphi 会帮你释放。但此时 AnsiString 不能和 PAnsiChar 一起使用。要得到内存的地址,可以使用 Pointer(AStr)。

【WideString】

  WideSting 和 AnsiString 的用法基本一样,也是动态分配内存。所不同的是,WideString 所存储的任何字符(不管是英文还是汉字)都是使用 2 个字节,但是 WideString 没有引用计数。其实 WideString 是为了方便使用 COM 而产生的,也就是 BSTR 字符串。BSTR 没有引用计数,效率较低。

  与 WideString 相对应的类型有 WideChar,用法与 AnsiChar 一样。还有 PWideChar,用法与 PAnsiChar 一样。

  Length 函数对于 WideString 来说,返回的就是字符数,而不是字节数,要获取 WideString 的字节数,直接把 Length 的返回值乘以 2 就可以了。

  对于如下代码而言:

----------

var
  WStr: WideString;
begin
  WStr := ‘123你好吗‘
end;

----------

  WStr[1] 就表示字符“1”,WStr[4] 就表示字符“你”,只不过此时的 WStr[1] 是 WideChar 类型(双字节)。

二、Delphi 2009 之后的字符串(开始全面支持 Unicode):

  Delphi 2009 之后又加入了一种新的字符串:UniodeString,并且对字符串的结构也做了改动,增加了 codePage 和 elemSize 域。下面是 System 单元中定义的字符串结构:

PStrRec = ^StrRec;
StrRec = packed record
  codePage: Word;   // 代码页:Unicode、UTF-8、UTF-16、GB2312
  elemSize: Word;   // 元素大小:一字符占几个字节
  refCnt: Longint;  // 引用计数:字符串被几个字符串变量使用
  length: Longint;  // 字符串长度:字节数
end;

  这个结构只用于 AnsiString 和 UnicodeString,也就是说在 AnsiString 和 UnicodeString 的字符串之前的 4 个字节存放的是字符串长度,再之前的 4个字节存放的是字符串的引用计数,再之前的 2 个字节存放的是元素大小,再之前的 2 个字节存放的是字符串的代码页。而 WideString 依然是原来的样子,没有变化。所以我们以后可以直接使用 UnicodeString 来处理汉字。

  在 system 单元中还定义了 UTF8String 和 UCS4String 类型的字符串,定义如下:

UTF8String = type AnsiString(65001);
UCS4String = array of UCS4Char;  { UCS4Char = type LongWord; }

  除此之外,Delphi 还定义了 RawByteStrng 类型的字符串,定义如下:

RawByteString = type AnsiString($ffff);

  关于RawByteStrng 类型:在将 AnsiString 格式的字符串赋值给 UTF8String 格式的字符串时,Delphi 会自动进行格式转换(还有其它格式的自动转换),所以,如果我们有一个函数的参数需要接收各种类型的字符串时,那么就很难实现,因为在传递参数的时候,Delphi 就会自动进行格式转换,所以,Delphi 定义了 RawByteString 类型,这种类型的变量在接收任何格式的字符串时,都会保持源字符串的内存格式,不做任何改动。

【string】

  我们平时经常使用的字符串类型是 string 类型,很少直接使用 AnsiString 或 UnicodeString,那么 string 是什么类型呢?

  string 类型根据编译参数的不同,所代表的含义也不同,或者说根据 Delphi 版本的不同,所代表的含义也不同,在 Ansi 版本(Delphi 2009 之前)中,string 就代表 AnsiString,而在 Unicode 版本(Delphi 2009 之后)中,就代表 UnicodeString。

  同样的 Char 在 Ansi 版本中就代表 AnsiChar,在 Unicode 版本中就代表 WideChar。PChar 在 Ansi 版本中就代表 PAnsiChar,在 Unicode 版本中就代表 PWideChar。

  在 Delphi 的 Unicode 版本中有一个新的函数 ByteLength 用来获取字符串的字节数。但是这个函数只能用于 string 类型的变量,我们看一下它的源代码就知道为什么了。

----------

function ByteLength(const S: string): Integer;
begin
  Result := Length(S) * SizeOf(Char);
end;

----------

  这个函数会根据不同的编译条件产生不同的计算结果,所以只能配合 string 使用。如果你将它用于 AnsiSting 或 UnicodeString 型变量,则在不同的编译条件下,有可能会出现错误。请看下面的代码:

----------

{ 在一个空白窗体上放置一个 TMemo 和一个 TButton }
procedure TForm1.Button1Click(Sender: TObject);
var
  SStr: ShortString;
  AStr: AnsiString;
  UStr: UnicodeString;
  WStr: WideString;
  Str: string;
begin
  SStr := ‘123你好吗‘;
  AStr := ‘123你好吗‘;
  UStr := ‘123你好吗‘;
  WStr := ‘123你好吗‘;
  Str  := ‘123你好吗‘;

Memo1.Clear;
  Memo1.Lines.Add(IntToStr(Length(SStr)));      { 结果 9  }
  Memo1.Lines.Add(IntToStr(Length(AStr)));      { 结果 9  }
  Memo1.Lines.Add(IntToStr(Length(UStr)));      { 结果 6  }
  Memo1.Lines.Add(IntToStr(Length(WStr)));      { 结果 6  }
  Memo1.Lines.Add(IntToStr(Length(Str)));       { 结果 6  }

Memo1.Lines.Add(IntToStr(ByteLength(SStr)));  { 结果 12 }
  Memo1.Lines.Add(IntToStr(ByteLength(AStr)));  { 结果 12 }
  Memo1.Lines.Add(IntToStr(ByteLength(UStr)));  { 结果 12 }
  Memo1.Lines.Add(IntToStr(ByteLength(WStr)));  { 结果 12 }
  Memo1.Lines.Add(IntToStr(ByteLength(Str)));   { 结果 12 }
end;

----------

时间: 2024-10-20 17:18:24

(转)Delphi 中的字符串的相关文章

关于Delphi中的字符串的详细分析

关于Delphi中的字符串的详细分析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short String) 长字符串(Long String) 宽字符串(Wide String) 零结尾字符串(Null-Terminated String).PChar和字符数组 1.短字符串(Short String) 固 定长度,最大字符数个数为255,短字符串也成为长度字节(Length-byt

关于Delphi中的字符串的浅析(瓢虫大作,里面有内存错误的举例)

关于Delphi中的字符串的浅析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short String) 长字符串(Long String) 宽字符串(Wide String) 零结尾字符串(Null-Terminated String).PChar和字符数组 1.短字符串(Short String) 固定长度,最大字符数个数为255,短字符串也成为长度字节(Length-byte)字

比较C/C++和Delphi中的字符串和字符数组(数组和动态分配内存的情况)

本文所讲解的只是从其中一个方面来看待进行的总结,所以有必要结合<Delphi字符串与字符数组之间的转换(初始化的重要性)>等文章进行更全面的了解,会从更多方面来理解字符串.内存.类型转换 C/C++中的字符串.字符数组.字符指针分配的内存空间 我们知道在C/C++中,我们可以这样理解字符串和字符数组 1)字符串,就是一个以 '\0' 结尾的字符数组 2)字符数组,包括字符串,但是不一定要以 '\0' 结尾,如果不是以'\0' 结尾,那么就不能当做字符串使用 在C/C++中,使用字符串可以通过数

Delphi中分隔字符串函数的使用

下面介绍Delphi自带的字符串分割函数,根据你的需要来使用. 1.ExtractStrings function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer; 第一个参数是分隔符,可以是多个,例如 [';',',',':'] 可以按分号.逗号.分号来同时分割. 第二个参数是开头被忽略的字符,例如['<','>',''],被分割出的字符,如果开头有

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能)

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能) 分类:            Delphi2007-05-16 11:094911人阅读评论(2)收藏举报 delphiintegerstringbutton文本编辑function 今天偶尔要做的Delphi程序,其中涉及到了字符串处理,里面有一个功能类似于VB里的split()函数的功能,于是查了很久才查到些资料,现将这些资料整理一下,方便大家. 首先是一个网友自己编的函数.实现了和split()函数的功能. unit U

Delphi 中Format的字符串格式化使用说明(转)

源:Delphi 中Format的字符串格式化使用说明(转) 一.Format函数的用法 Format是一个很常用,却又似乎很烦的方法,本人试图对这个方法的帮助进行一些翻译,让它有一个完整的概貌,以供大家查询之用: 首先看它的声明: function Format(const Format: string; const Args: array of const): string; overload; 事实上Format方法有两个种形式,另外一种是三个参数的,主要区别在于它是线程安全的,但并不多用

Delphi中stringlist分割字符串的用法

Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaText 2.Delimiter &DelimitedText 3.Names &Values &ValueFromIndex 先看第一个:CommaText.怎么用呢? const constr :String = 'aaa,bbb,ccc,ddd'; var strs :TStrin

delphi中的Format函数详解

首先看它的声明:[[email protected]][@21ki!] function Format(const Format: string; const Args: array of const): string; overload;[[email protected]][@21ki!] 事实上Format方法有两种形式,另外一种是三个参数的,主要区别在于它是线程安全的,[[email protected]][@21ki!]但并不多用,所以这里只对第一个介绍:[[email protect

Delphi中Android运行和JNI交互分析

Androidapi.JNIBridge负责和JNI交互.,既然要交互,那么首先就是需要获得JNI的运行环境,Android本身内置的就有一个Java(Dalvik)虚拟机.所以这个第一步就肯定是要这个虚拟机和我们当前的运行线程环境关联.这时候Androidapi.JNIBridge中的TJNIResolver就出场了.GetJNIEnv这个函数就是, [delphi] view plaincopy class function TJNIResolver.GetJNIEnv: PJNIEnv;