请教各位大虾:如何判断一个字符串的最后一位是不是null(即#0)
解决方案 »
- 用什么代码可以实现生成一个ToolButton?
- ComboBox的items 怎么往里面写内容呢,用程序,能够真正写进去呢? 在线等.....
- 怎样合并字符串?
- 快来帮忙
- 怎样制作可执行程序?我的程序只有在开发用的机器上才能运行。在线等待
- object pascal佳篇推荐!
- 兄弟姐妹,快点来,救,急
- 超级难题,连续打印表格
- 如果使用toolbar,怎样让boolbarbutton显示256色的图片.
- 出 500 分 外加人民币 200 元购买一份源程序(代理服务器软件,要求能分别让各机在不同时间内限上网,最好有日志记录)1/x
- 请问Form的Destroy和Close有什么区别?
- 程序调试时如何一次显示出某一TStrings类型变量的全部值?
strlen:integer;
begin
strlen:=length(str);
if str[strllen]=#0 then
showmessage('it is null');
end;
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array of Char;
end;并且szBuf的最后一位为#0,所以这里如果想判断,可以如下进行(指向AnsiString的指针指向AnsiString的偏移为0,既szBuf的第一个字符处):if (Pchar(Str)+StrLen(PChar(Str)))^=#0 then ....
把分给fs 吧 他说得不错
她只是与空结束的字符窗相兼容 无长度限制
除非你自己强制添加空结束 要不然最后一位不会是空
pchar 是自己强制添加的 所以为避免内存错误dll中都用pchar 这个我想大家都知道
其实一楼的方法可以判断强制添加的空字符
s:string; s:='1234'#0#0'34';
ShowMessage(IntToStr(Length(s)));// 显示 8
ShowMessage(IntToStr(StrLen(PChar(s)))); //显示 4所以,string 中可以存储 #0, 而 PChar 是以 #0 终结
而StrLen返回的长度不包括最后的#0,所以这里不应该加1,呵呵!另外,使用Length来返回长度也是不包括最后一个空字符的....
而StrLen返回的长度不包括最后的#0,所以这里不应该加1,呵呵!另外,使用Length来返回长度也是不包括最后一个空字符的....
除非你自己
var s:string;
s:='12345678';
S[Length(s)]=#0;
ansistring和pchar的区别大家都知道,为什么object pascal要弄一个ansistring,而不是直接使用c/c++里的pchar(当然c/c++里不叫pchar,而叫char*)?就是为方便使用,为什么非要给ansistring后面加一个0呢?
世界变了,人也变了。
ansistring和pchar的区别大家都知道,为什么object pascal要弄一个ansistring,而不是直接使用c/c++里的pchar(当然c/c++里不叫pchar,而叫char*)?就是为方便使用,为什么非要给ansistring后面加一个0呢?
世界变了,人也变了。
string,ansistring: 则最后一个字符是 s[Length(s)]。
PChar: 则必须以 #0 终结,否则,将访问到其它空间。
var t,i,n:integer;s,phone_t,time_t,cnt_t,str:string;ps:pchar;
begin
fjstr:=tmp_r+fjstr;
n:=length(fjstr);
//showmessage(inttostr(n));
i:=0;
ps:=pchar(fjstr);
while i<n do
begin
if rightstr(ps,1)=#0 then
begin
showmessage('#0')
{tmp_r:='';
t:=strlen(ps);
s:=stringofchar('a',t);
strcopy(pchar(s),ps);
i:=i+t+1;
ps:=ps+t+1;
form1.memo3.Lines.Add(datetimetostr(now)+' '+s+#13#10+inttostr(t)); //信息格式为:手机号码(11):时间(14):内容#0手机号码(11):时间(14):内容...
time_t:=leftstr(s,14);//time_t是发送时间
phone_t:=leftstr(s,26);
phone_t:=rightstr(phone_t,11);//phone_t是发送手机号码
cnt_t:=rightstr(s,t-27); //cnt_t是发送内容
str:='update lymud set flag=2,gettext='''+cnt_t+''' where phone='''+phone_t+''' and createtime='''+time_t+'''';
with aq3 do
begin
close;
SQL.Clear;
SQL.Add(str);
ExecSQL;
end
end
else
begin//说明最后一条信息没有发送完整
{t:=strlen(ps);
tmp_r:=stringofchar('a',t);
strcopy(pchar(tmp_r),ps);
showmessage('not #0');
end;
end;
end;
tmp_r是在这个位置定义的全局变量:var
Form1: TForm1;
tmp_r:string;
implementation
var
S1,S2:String; //这个时候由于你没有改变{$H}编译指令的默认状态,所以编译器认为你这里申明的是AnsiString,除非你后面指定了长度
begin
S1:='I am an AnsiString!'; //实际上S1是个指针,指向堆中的具体AnsiString存放地址偏移为0的地址,并且到这里引用记数加1
S2:=S1; //到这里引用记数再加1,为2
S2:='I am another AnsiString!'; //到这里,由于S2的长度改变,和S1不一致,所以开始单独分配空间,并且原有引用记数减1,同时S2引用记数加1AnsiString的长度是动态分配的!明白?
end;
但 PChar 占用的空间包括这个 #0 所占的空间
但 PChar 占用的空间包括这个 #0 所占的空间
能不能举个简单的例子说明一下这些类型的关系啊,比如string,ansistring,widestring,pchar,pwidechar,不问还可以,一问现在脑子一团糟,谢谢了!
s:string;
pc:PChar;
i:Integer; s:='1234';
GetMem(PC,Length(s)+1);
for i:=1 to Length(s) do
PC[i-1]:=s[i]; PC[i]:=#0;
s:string;
pc:PChar;
i:Integer; s:='1234';
GetMem(PC,Length(s)+1);
for i:=1 to Length(s) do
PC[i-1]:=s[i]; PC[i]:=#0;
s:string;
pc:PChar;
i:Integer; s:='1234';
GetMem(PC,Length(s)+1);
for i:=1 to Length(s) do
PC[i-1]:=s[i]; PC[i]:=#0;
我是指如果要把一个 string 传给一个 PChar 类型,给 PChar 分配空间时,要比字符串长度多 1 个空间。
var
s:string;
pc:PChar;
i:Integer; s:='1234';
GetMem(PC,Length(s)+1);
for i:=1 to Length(s) do
PC[i-1]:=s[i]; PC[i]:=#0;
var
S:String[32]; //这里因为指定了长度,所以虽然处于{$H+}状态仍然为ShortString这里的长度最长可以指定为255,如果指定长度超过255,比如256,马上就会报一个编译错误,警告越界!这说明虽然处于{$H+}状态,但指定长度仍然不能超过ShortString的范围限制!AnsiString是由AnsiChar字符组成的,而对于WideString则是有WideChar组成的,也就是宽字符,实际上就是两个字节!这样做的目的是为了满足使用Ansi字符集无法表示的字符,例如中文字符,WideChar使用Unicode字符集,几乎可以表示任何字符,对于WIN NT以下的操作系统不支持Unicode字符集!所以WideString和AnsiString没有多大的区别,唯一区别就是组成的字符大小不一致!对于PChar、PAnsiChar和PWideChar都是指针,所以长度永远都是四个字节,分别指向Char、AnsiChar和WideChar组成的以Null结尾的字符串!最后就是Char、AnsiChar和WideChar的区别:
Char目前相当于AnsiChar,将来版本的Delphi中相当于WideChar。这里的意思可能是将来Ansi字符集或许会废弃不用,全部使用Unicode 字符集!
WideChar是2字节的Unicode字符;而AnsiChar就是1个字节的Ansi字符!好了,就这么多了,更加详细的内容网络上可以查到很多.....
你说AnsiString类型的结构如下:
strAnsi = record
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array of Char;
end;
那请问我为什么不能跟操作结构类型一样的操作AnsiString呢?
还用你怎么知道它的结构是这个样子的?有点不合理吧,怎么会是这样的呢?
| 分配大小 | 引用计数 | 长度 | 具体字符串内容 .... | #0 |
----------------------------------------------------------------
对于以Null结尾的字符,都是动态分配空间的,而且没有255的长度限制,而我们上面所说的PChar、PAnsiChar和PWideChar都是指针,他们的内容所指向的偏移为0的地址应该都是上图从左到右第四段那里的起始地址........
帮助中有这么一段
A long string variable occupies four bytes of memory which contain a pointer to a dynamically allocated string. When a long string variable is empty (contains a zero-length string), the string pointer is nil and no dynamic memory is associated with the string variable. For a nonempty string value, the string pointer points to a dynamically allocated block of memory that contains the string value in addition to a 32-bit length indicator and a 32-bit reference count. The table below shows the layout of a long-string memory block.Offset Contents
-8 32-bit reference-count
-4 length in bytes
0..Length -1 character string
Length NULL character
The NULL character at the end of a long string memory block is automatically maintained by the compiler and the built-in string handling routines. This makes it possible to typecast a long string directly to a null-terminated string.
For string constants and literals, the compiler generates a memory block with the same layout as a dynamically allocated string, but with a reference count of ?. When a long string variable is assigned a string constant, the string pointer is assigned the address of the memory block generated for the string constant. The built-in string handling routines know not to attempt to modify blocks that have a reference count of -1.ansiString应该是这里的long string吧,它的结构
Offset Contents
-8 32-bit reference-count
-4 length in bytes
0..Length -1 character string
Length NULL character
好像和你的有点出入哟
要把一个 string(中间没有#0) 传给一个 PChar 类型,
给 PChar 分配空间时,可肯定要比字符串长度多 1 个空间。
var
s:string;
pc:PChar;
i:Integer; s:='1234';
GetMem(PC,Length(s)+1);
move(s[1],pc[0],Length(s)+1);
给 PChar 分配空间时,可肯定要比字符串长度多 1 个空间。”为什么这么说?var
s:string; //这里如果编译指令为{$H+},那么这里这个S就是一个AnsiString类型变量
pc:PChar;
i:Integer; s:='1234'; //这里不知道楼上认为分配多少个空间,个人认为分配空间大小为4+4+4+1*4+1=17个字节的空间
GetMem(PC,Length(s)+1); //为什么要给PChar这样分配空间?
move(s[1],pc[0],Length(s)+1);
分配Refcount(4)+Lenth(4)+实际字符串(4)+#0(1)
对于最后的#0,AnsiString绝对是要分配的,否则Pchar(s)根本不可能实现!!!
Borland不可能为Pchar(s)重新分配内存,也没有此必要,因为已开始已分配了Length(s)+1的空间,并且确保s[length(s)]=#0,所以中间含有#0的AnsiString其实非常危险,特别是Pchar(s)的调用肯定会出问题!!!
一句话,若没有特殊理由的话,AnsiString S 中间就不应该有#0,但是它的
最后S[Length(S)+1]不是S[Length(S)],则肯定为0!!!
打字真累!!!
pc:=PChar(s);
这样的话,当然不需要为 PC 分配空间。
而我的意思是把 s 的内容复制到由 PC 所指向的一块内存空间,这时,为 PC 分配空间时就要多一个 #0 的空间了。
var p:pchar;
s:string;
s:='12345678';
分配Refcount(4)+存放实际长度(4)+实际字符串(8)+#0(1)
是不是这样分配空间可以去问Borland
p:=Pchar(s);
简单的PChar(s)强制转换,确实是没有再重新分配内存,因为S已经分配了内存
但是如果要复制它,则要分配Length(s)+1个空间
getmem(p,Length(s)+1);
strcopy(p,pchar(s));//p结尾自动加#0;难道这还有疑问!!!
getmem应该是给指针指定一个可操作的地址范围(内存空间)
strcopy就应该是将具体的字符串copy到这个地址范围(内存空间)里,这个地址就是指针指向的地址所以,大家都是正确的
s:string;
itemp:integer;
begin
s:='My name is delphi';//17个字节
itemp:=integer(pointer((integer(@s[1])-4))^); //字符串长度等于17 正确
showmessage(inttostr(itemp));
itemp:=integer(pointer((integer(@s[1])-8))^); //引用计数等于1 正确
showmessage(inttostr(itemp));
itemp:=integer(pointer((integer(@s[1])-12))^); //占用空间等于34 不正确 应该是:4+4+4+17+1=30;
showmessage(inttostr(itemp));
end;FrameSniper你如何解释?
var
s:string;
itemp:integer;
begin
s:='My name is delphi';//17个字节
itemp:=integer(pointer((integer(@s[1])-4))^); //字符串长度等于17 正确
showmessage(inttostr(itemp));
itemp:=integer(pointer((integer(@s[1])-8))^); //引用计数等于1 正确
showmessage(inttostr(itemp));
itemp:=integer(pointer((integer(@s[1])-12))^); //占用空间等于34 不正确 应该是:4+4+4+17+1=30;
showmessage(inttostr(itemp));
end;你如何解释?
strAnsi = record
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array of Char;
end;这是我前面给出的结构示意,和你说的4+4+4+17+1的结果有什么区别吗?
按你给的结构,占用4+4+4+17+1=30个字节,没错吧?我这样计算s占用空间:
integer(pointer((integer(@s[1])-12))^); //应该没错吧?
为什么占用了34个字节?
strAnsi = record
nSize: Integer;//4
nRef: Integer; //4
nLength: Integer;//4
szBuf: array[0..0] of Char; //4
end;
所以应该是4+4+4+4+17+1
strAnsi = record
nSize: Integer;//4
nRef: Integer; //4
nLength: Integer;//4
szBuf: array[0..0] of Char; //4
end;
所以应该是4+4+4+4+17+1需要明白的一点是,AnsiString本身就是一个指针,这个指针指向的是堆栈中的字符串第一个字符的位置上!如果你说这里的szBuf前面还有一个指针,我不明白这个指针里面保存的内容是什么,因为这个结构表示的内存空间应该是在堆栈上的!
我是没搞董,为什么szBuf已经占用了17个字节,它还占有一个指针(4个字节)的空间?
我想,既然szBuf是一个指针,那就应该占有一个4字节的空间
那么,s(AnsiString)也是一个指针,为什么就不该再占用4字节的空间呢?
难道s这个指针恰好和szBuf这个指针重合(就是一个地址)?这样就解释清楚了?
所以FrameSinper给出的ansistring的结构才是正确的?help中的结构是不全的?
贴出BCB的源码片断: class RTL_DELPHIRETURN AnsiString
{
...
protected:
...
struct StrRec {
int allocSiz;
int refCnt;
int length;
};
...
private:
// assert(offsetof(AnsiString, Data) == 0);
char *Data;
};
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array[0..0] of Char;
end;
这个结构肯定不是在一个连续的空间上,所以szBuf仅仅是一个指针,它的值应该在另一段空间中,所以导致整个空间多了4个字节,不知道是不是这样?
早年的Pascal对字符串的定义是这样的:
str = record
nLen : Byte;
szBuf: array[0..0] of Char;
end;所以,在Pascal里,字符串的第一个字符是[1],而不是像C一样是[0],因为在Pascal里[0]是串长度,所以Pascal的串长度限制为255个字符。DELPHI作了改进,将原来的Pascal String定义为ShortString,而新的String其实就是AnsiString,至于AnsiString的结构是怎么样的,那就不知道了。也许会继承传统,如各位前面所述,也有可能与BCB统一,用BCB的实现方式。
我想这两者的区别就大了
A long-string variable is a pointer occupying four bytes of memory.
long string要占据4个字节的内存,所以szBuf根本就不存在4个字节的指针空间那么
s:='My name is delphi';//长17
strAnsi = record
nSize: Integer;//4
nRef: Integer; //4
nLength: Integer;//4
szBuf: array[0..16] of Char; //17,不存在4字节的指针
end;
另外4个字节就是s指针(指向整个结构),也就是ansistring变量,还有一个null,所以s共占去34个字节这样对否?
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array[0..0] of Char;
end;
szbuf其实就是Ansistring的指针
strAnsi = record
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: pChar;
end;
szbuf
现在小弟正在学汇编,请多指教,在此谢过
然后,根据nLen创建一个Instance
在NewInstance时,计算所需要空间:
nSize := ( nLen + 10 ) and ( -2 ); // nLen=$11时,nSize=$1A
估计上述算法是基于:加上8Byte的nRefCnt和nLen,及最后一个#0,然后按16bit Word对齐
然后,调用GetMem分配内存,设分配的地址为pAddr
其结构如下:
strAnsi = record
unknown : Integer;
nSize : Integer;
nRefCnt : Integer; // pAddr指向这里
nLen : Integer;
szBuf : Array [0..17] of char; // 包括最后的#0所占空间
end;
然后,将Result设置为pAddr+$8(即指向szBuf)
再把nLen赋给strAnsi.nLen,把1(refCnt)赋给strAnsi.nRefCnt好啦,分析完毕,显然:
一个String的Instance中只包括:nRefCnt,nLen,szBuf三部分,前面的nSize是分配内存时留下的,至于nSize前面一个是什么东东,偶也不知道了,应该是DELPHI内存管理用的东东,这也就是为什么nSize总是会多出来的四个byte了。
@LStrFromPCharLen:根据一个长度来创建一个String的Instance
@NewAnsiString:根据Len创建一个新的String Instance
@GetMem:分配内存有兴趣的可以自己在CPU Windows里看:)
我喜欢以上大虾们的这种辩论
能让人深入的了解Delphi底层的东西,有益我等菜鸟的健康成长
佩服
感谢大虾们