Delphi中的各种字符串、String、PChar、Char数组
参考博客:http://www.cnblogs.com/pchmonster/archive/2011/12/14/2287686.html
其中的所有代码均在Delphi7下测试通过。
Delphi 4,5,6,7中有字符串类型包括了:
- 短字符串(Short String)
- 长字符串(Long String)
- 宽字符串(Wide String)
- 零结尾字符串(Null-Terminated String)、PChar和字符数组
1、短字符串(Short String)
固定长度,最大字符数个数为255,短字符串也称为长度字节(Length-byte)字符串,这是因为短字符串的第0个元素包含了这个字符串的长度(字符串中字符的个数)。因此ShortString的缺省最大长度为256个字节(255个字符+1个长度字节=256),声明一个短字符串有两种方式,如下:
var
S: ShortString; { 255个字符长度,256个字节}
S1: String[255]; { S1和S的字符类型一样,通过使用String声明字符串并且在String后面用中括号规定字符个数的形式定义字符串}
Len: Integer;
begin
S := 'Hello';
Len := Ord(S[0]); { Len现在包含S的长度为5,Ord函数可以把一个字符类型转换为整数类型}
Len := SizeOf(S); { Len现在包含的是ShortString类型的大小,为256字节,并不是字符串的长度}
end;
以上例子通过S[0]可以获得S的字符串长度,当然也可以用Length函数来确定一个短字符串的长度。
可以通过数组的下标来访问ShortString中的一个特定位置的字符,具体使用参看下面例子和注释说明:
var
S: string[8];{这种定义方式,是定义S是一个字符串,且S是最多含有8个字符的字符串}
i: Integer;
begin
S := 'a_pretty_darn_long_string';
{ 因为S只有8个字符大小,
因此s的实际存储的内容为“a_pretty”}
i := 10;
S[i] := 's';
{ 因为S只有8个字符大小,
试图改写第10个元素,将会使内存混乱}
end;
2、长字符串(Long String)
长字符串 (AnsiString)是一种动态分配的字符串,其大小只受可用内存的限制。声明一个长字符串,只需要用关键字String不加大小参数即可。
在Delphi 7中AnsiString包含的字符是用单字节存储的。
var
S: string;
由于是动态分配的,一次可以随意修改字符串,而不用担心对其他的影响,也不用担心越界的问题。String类型没有0元素,试图存取String类型的0元素会产生一个编译错误。
通过Length函数也可以获得长字符串的长度,也可以通过SetLength过程为长字符串设置长度。其在内存中分配情况如下:
注意当给一个String类型赋值时候,赋的字符串太长,可能会报错:“String literals may have at most 255 elements”。这时候你就纳闷了:不是说String的字符个数没有限制的吗?
对于这个问题,我们给个代码示例(程序1)
var
s: string;
begin
s:= '<?xml version="1.0" encoding="UTF-8"?><Msg><AppHdr><CharSet>UTF-8</CharSet><Fr>000100</Fr><To>SDC</To><BizMsgIdr>0000000002</BizMsgIdr><MsgDefIdr>V1.0</MsgDefIdr><BizSvc>067</BizSvc><CreDt>20130227100434</CreDt><Sgntr>fb3LY5VmhonZwhP+ntxI9A==</Sgntr></AppHdr><Document><Data><FndNm>name</FndNm><TtlFndVol>12681656.00</TtlFndVol><FndCd>159999</FndCd><FndSts>0</FndSts><NAV>1.0251</NAV><NtValDt>20130301</NtValDt><NtValTp>0</NtValTp></Data></Document></Msg>'; end.
这个时候,将一个长度大于255的字符串直接赋值给string类型的变量就会报上面所说的错误。可以替代的办法是将一个较长的字符串分成多份,在赋值时候使用+ 再赋值,见例子(程序2)
var
s: string;
begin
s:= '<?xml version="1.0" encoding="UTF-8"?><Msg><AppHdr><CharSet>UTF-8</CharSet><Fr>000100</Fr><To>SDC</To>'
+ '<BizMsgIdr>0000000002</BizMsgIdr><MsgDefIdr>V1.0</MsgDefIdr><BizSvc>067</BizSvc><CreDt>20130227100434</CreDt>'
+ '<Sgntr>fb3LY5VmhonZwhP+ntxI9A==</Sgntr></AppHdr><Document><Data><FndNm>FundName</FndNm><TtlFndVol>12681656.00</TtlFndVol>'
+ '<FndCd>159999</FndCd><FndSts>0</FndSts><NAV>1.0251</NAV><NtValDt>20130301</NtValDt><NtValTp>0</NtValTp></Data>'
+ '</Document></Msg>'; end.
这个时候就可以编译成功了
3、宽字符串(Wide String)
宽字符串和长字符串一样,大小只受有效内存的限制,并实行动态分配。
在Delphi 7 中WideString被实现为2个字节存储一个字符,用WideString来处理多字节字符(比如汉字)是十分方便的。如:
var
S: string;
{ 在Delphi 7中默认string等同于AnsiString}
WS: WideString;
begin
S := '世界你好';
WS := S;
ShowMessage(S[1]); { 此时无任何显示,因为S[1]取出的是‘世’的一半}
ShowMessage(WS[1]); { 显示‘世’}
end;
要理解宽字符串就必须理解字符编码的规则,比如ASCII、UTF-8……
4、零结尾字符串(Null-Terminated String)、PChar和字符数组
在C和C++中没有真正的字符串数据类型,都是通过以Null结尾(0)的字符数组来实现的,字符数组没有长度字节,因此只能通过结尾的Null标志来作为字符串的字符结束标志。又因为Windows是用C编写的,很多Windows函数要用到以字符数组作为参数,但Pascal字符串类型不是字符数组,因为为了让Pascal字符串也能与Windows兼容,就需要一个字符串数组,PChar类型正是符合这种需求,在任何需要字符数组的地方都可用PChar。
虽然AnsiString和WideString都已经实现了NULL
相应的也有PAnsiChar和PWideChar,分别对应于AnsiChar字符和WideChar字符。
例如:Windows MessageBox函数,此函数声明如下:
function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;
第二个和第三个参数需要一个指向字符数组的指针,为了可以调用此函数,有以下三种方法来实现
1、PChar()类型转换
var
Text: string;
Caption: string;
begin
Text := 'This is a test.';
Caption := 'Test Message';
MessageBox(0, PChar(Text), PChar(Caption), 0);
{ 这里PChar用来把string类型转换为Null结尾的字符串}
end;
其中
2、PChar变量
我们先做一个实现,看看PChar类型到底是啥呢?
运行下面程序:
var
Text: PChar; { 声明为PChar类型}
Str: string; { 声明为String类型}
begin
Text := 'This is a test.'; { 都被赋予了相同的字符串}
Str := 'This is a test.';
ShowMessage(IntToStr(SizeOf(Text))); { 4字节,实质是指针}
ShowMessage(IntToStr(SizeOf(Str))); { 也是4字节,也是指针}
end;
通过上面的程序,我们知道Text(PChar类型)只不过是一个指针而已。
var
Text: PChar;
begin
Text := 'This is a test.';
MessageBox(0, Text, 'Test Message', 0);
{ 这里Text直接声明为了PChar类型,字符串常量可以直接用}
end;
指针Text指向了这样一个内存区域,一个包含Null的结尾的 'This is a test.' 字符串的区域。其等同于下面的代码:
const
TempString: array[0..15] of Char = 'This is a test.'#0;
var
Text: PChar;
begin
Text := @TempString[0];
{Text指向Null结尾的TempString字符数组的第0个元素的地址,
也就是整个字符数组的首地址}
MessageBox(0, Text, 'Test Message', 0);
end;
3、Char类型字符数组
最后还可以用Char数组来代替PChar,代码如下:
小心内存访问越界的情况的出现
var
Text1: array[0..14] of Char; { 大小为15个字符}
Text2: array[0..20] of Char; { 大小为21个字符}
begin
Text1 := 'This is a test.'; {Text1和Text2的字符长度都为15个字符}
Text2 := 'This is a test.';
MessageBox(0, Text1, 'Test Message 1', 0);
{因为Text1的字符长度超过了其声明的大小,因为会内存访问混乱,显示换乱} MessageBox(0, Text2, 'Test Message 2', 0);
{Text2的字符长度比起声明的大小要小,因为正常访问,显示正确}
end;
显示结果如下:
关于字符串就先浅浅的谈到这个,以后再深入了解。
Delphi中的各种字符串、String、PChar、Char数组的更多相关文章
- Delphi中stringlist分割字符串的用法
Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaT ...
- PChar,PAnsiChar,String,AnsiString,Char数组,AnsiChar数组转换
PChar,PAnsiChar,String,AnsiString,Char数组,AnsiChar数组之间的转换关系见下图 通过转换链,可以实现任意两个类型之间的互转.如PChar转PAnsiChar ...
- Delphi 中Format的字符串格式化使用说明(转)
源:Delphi 中Format的字符串格式化使用说明(转) 一.Format函数的用法 Format是一个很常用,却又似乎很烦的方法,本人试图对这个方法的帮助进行一些翻译,让它有一个完整的概貌,以供 ...
- 在Delphi中使用ShellExecute(handle, 'open', PChar(fname),nil, nil, SW_HIDE)函数应注意的问题
在Delphi中使用ShellExecute(handle, 'open', PChar(fname),nil, nil, SW_HIDE)函数应注意的问题: 一.对一般vcl程序及isapi dll ...
- Leetcode541/151之String与char数组与StringBuffer
String与char数组与StringBuffer 通常情况下遇到删除字符或者反转字符串时需要将String转为char数组或者StringBuffer String与char数组 char [] ...
- Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar(来自http://delphi.cjcsoft.net/论坛)
Delphi有三种类型的字符: AnsiChar这是标准的1字节的ANSI字符,程序员都对它比较熟悉. WideChar这是2字节的Unicode字符. Char在目前相当于AnsiChar,但在De ...
- delphi string,pchar,char的比较
来自:http://blog.163.com/kat_/blog/static/189284269201152513331999/ ---------------------------------- ...
- [转]:Delphi中Format的字符串格式化使用说明
一.Format函数的用法 Format是一个很常用,却又似乎很烦的方法,本人试图对这个方法的帮助进行一些翻译,让它有一个完整的概貌,以供大家查询之用: 首先看它的声明: function Forma ...
- Delphi中返回类型为string的函数的一个陷阱(不是很懂)
如果类的一个成员函数的返回值是string类型,需要注意一个问题 其返回值可能是错误的 例如函数的实现如下 function GetString( s: string ): string;begin ...
随机推荐
- Mysql报错Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist
安装mysql后,启动时候没有启动成功,查看了下日志报错如下:---------------------------------------------1 可以:初始化mysql:mysql_in ...
- U盘安装中标麒麟服务器操作系统 一 (NeoKylin 6.5)
U盘安装中标麒麟服务器操作系统(NeoKylin 6.5) 首先需要下载中标麒麟服务器操作系统的iso镜像.我这里的是NeoKylin Linux A 6.5.iso 因为超过了4GB,百度网盘不支持 ...
- Ubuntu 15.10下droidbox安装使用
DroidBox是一个动态分析Android代码的的分析工具.其目前的安装环境为:Linux/Unix/MacOSX 下面是安装步骤 一. 安装Android SDK 并添加环境变量 export P ...
- 【GoLang】golang中 channel 实现同步 与mutex/atomic 实现同步的讨论
参考资料: https://groups.google.com/forum/#!topic/golang-china/q4pFH-AGnfs
- 转帖: 使用脚本删除程序(免除在[控制面板]->[添加或删除程序]中的手工操作)
1. 代码:VBS strComputer = "." '这个表示本地计算机 Set objWMIService = GetObject("winmgmts:" ...
- FlexPaper使用小结
FlexPaper相关介绍及后台swf生成,参见 FlexPaper实现文档在线浏览(附源码) 前台swf在flash中的预览: 1.下载相关文档 FlexPaper Classic 2.将下载的文件 ...
- 基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法
文章目录 1. 1. 摘要 2. 2. Map-Matching(MM)问题 3. 3. 隐马尔科夫模型(HMM) 3.1. 3.1. HMM简述 3.2. 3.2. 基于HMM的Map-Matchi ...
- gitlab 无法查看提交的文件Errno::ENOMEM (Cannot allocate memory - /opt/gitlab/embedded/bin/git):
gitlab可以成功clone和push,但是提交后的文件却无法查看.从页面上看的话只显示出500错误. 查了下gitlab的日志 tail -f /var/log/gitlab/gitlab-rai ...
- sqlite ORMLite 框架应用
bean package com.test.deamo.bean; import android.os.Parcel; import android.os.Parcelable; import com ...
- CEF3开发者系列之进程和线程
CEF3是一个多进程架构框架,如果有了解过chromium的进程架构的,那么就很容易了解CEF3的多进程了.打开CEF3源代码中发布的cefclient实例,如果打开的页面带有flash或者其他插件. ...