String类型其实是一个指向特定格式的内存块的指针,在Delphi1中,定义一个String类型的变量的方式为:
var nStr : PString;
在Delphi后来的版本后,直接使用String关键字,但其本身仍然是一个指向串的指针:
var nStr : String; Len : Integer; begin nStr := 'HelloWorld'; Len := Sizeof(nStr); //4 end;
Sizeof(nStr)其实是该指针的大小,并不是串的大小。判断串的大小需要用Length()方法。如果该指针为nil,则该串为空。否则则指向一个字符序列。
在Delphi中,String类型又分为:
ShortString, AnsiString, WideString.
在默认情况下:
var nStr1 : String; nStr2 : AnsiString;
使用String关键字申明的nStr1变量相当于nStr2.
一个长串(String/AnsiString)的内部情况如下:
偏移位置(Byte) -8 //(-8..-4)存储一个整型的引用计数,对于常量串,这个值置为-1。 -4 //(-4..0)存储一个整型的串长度 1..Length //存储串 Length + 1 //末尾追加一个NULL
注:WideString没有引用计数,其他与之相同。
对于两个串实现赋值
nStr1 := nStr2;
编译器会将其转换成两个步骤:第一先将nStr2的引用计数增加1,第二将nStr1指针置为与nStr2指针相同。
另外值得注意的是,如果将一个串传递到某个程序中,而且不打算对该串进行修改,那么最好的方式是将该串申明为const。因为如果没有申明为const(而且,这个串你正好也不需要修改),编译器就会认定你可能会修改它,因此就会建立一个局部不可见的串变量来保存它。使用时将它的引用计数增加,等使用完了就递减。编译器为了保证该串的引用计数能被递减以释放,会增加一个try .. finally块来确保。因此,在此会略微增加程序的开销。
如下:
function CountOfString1(nStr : String): Integer; var i: Integer; begin for i := 0 to Length(nStr) do if nStr[i] = '1' then inc(Result); end; function CountOfString2(const nStr : String): Integer; var i: Integer; begin for i := 0 to Length(nStr) do if nStr[i] = '1' then inc(Result); end; procedure TForm1.btn1Click(Sender: TObject); var i: Integer; Tick : Cardinal; begin Tick := GetTickCount; for i := 0 to 10000000 - 1 do CountOfString1('HelloWorld1'); ShowMessage(Format('%d', [GetTickCount - Tick])); //我的机器显示大致在240-250之间 end; procedure TForm1.btn2Click(Sender: TObject); var i: Integer; Tick : Cardinal; begin Tick := GetTickCount; for i := 0 to 10000000 - 1 do CountOfString2('HelloWorld1'); ShowMessage(Format('%d', [GetTickCount - Tick])); //我的机器显示大致在120- 130之间
end;
最后就是串的Pos()方法。
该方法是返回一个子串在一个更大的串中的位置。但是,如果我们要想知道某一个字符在某个大串中的位置,使用该方法,编译器又会做一些额外的操作,如下:
var nChar : Char; nStr : String; nPos : Integer; begin nPos := Pos(nChar, nStr); end;
使用上面的方式查找位置,编译器会自动将这个字符转换成一个长度为1的串。转换后再调用该Pos()函数。因为要调用一个自动的而且不可见的串,所以自然在使用结束后要将其释放,这里就会额外的用到try .. finally块来确保释放该串。
所以:
var i, nPos : Integer; nChar : Char; nStr : String; begin for i := 1 to Length(nStr) do begin if nChar = nStr[i] then bein nPos := i; Break; end; end; end;
使用该方式反而会比上面的方法更快一些。当然,如果本身就是要查找一个串在另一个串中的位置,也就没有这种可以略微减少开销的方式了。
再者,如果想要在串后面追加串:
nStr1 := nStr1 + nStr2;
一般我们都是这样做,使用‘+’连接符。
但是,如果我们要在串后面追加一个字符呢:
nStr1 := nStr1 + nChar;
如果使用这样的方法,那么编译器还是会将这个nChar转换成串。