请教各位大虾:如何判断一个字符串的最后一位是不是null(即#0)

解决方案 »

  1.   

    str:string;
    strlen:integer;
    begin
      strlen:=length(str);
      if str[strllen]=#0 then
         showmessage('it is null');
    end;
      

  2.   

    to fhuibo(Sailor) and 2353939(菜鸟) 强烈同意二位的法!的确像!
      

  3.   

    楼上的干什么啊?Delphi默认情况下{$H+}状态下申明的String类型为AnsiString,所以你要进行这种确认必须首先保证这个编译器指令为打开状态而对于AnsiString类型的字符串,结构如下:strAnsi = record
       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 ....
      

  4.   

    if (Pchar(Str)+StrLen(PChar(Str))+1)^=#0 then ....更正一下!
      

  5.   

    2 3 4 搂的回帖什么意思?最后空不空就是pchar 与string 的区别
    把分给fs 吧 他说得不错
      

  6.   

    靠 fs 不早说 $H+}状态下申明的String类型为AnsiString  没错而且默认的情况下
    她只是与空结束的字符窗相兼容 无长度限制 
    除非你自己强制添加空结束 要不然最后一位不会是空
    pchar 是自己强制添加的 所以为避免内存错误dll中都用pchar 这个我想大家都知道
    其实一楼的方法可以判断强制添加的空字符
      

  7.   

    var
      s:string;  s:='1234'#0#0'34';
      ShowMessage(IntToStr(Length(s)));// 显示 8
      ShowMessage(IntToStr(StrLen(PChar(s)))); //显示 4所以,string 中可以存储 #0, 而 PChar 是以 #0 终结
      

  8.   

    呵呵,实在不好意思,楼主,偶犯了个简单错误,这里应该是if (Pchar(Str)+StrLen(PChar(Str)))^=#0 then ....Pchar(Str)返回AnsiString中真正字符数组开始的第一位置
    而StrLen返回的长度不包括最后的#0,所以这里不应该加1,呵呵!另外,使用Length来返回长度也是不包括最后一个空字符的....
      

  9.   

    呵呵,实在不好意思,楼主,偶犯了个简单错误,这里应该是if (Pchar(Str)+StrLen(PChar(Str)))^=#0 then ....Pchar(Str)返回AnsiString中真正字符数组开始的第一位置
    而StrLen返回的长度不包括最后的#0,所以这里不应该加1,呵呵!另外,使用Length来返回长度也是不包括最后一个空字符的....
      

  10.   

    乖乖...我看不打一场是不行..谁胜我就支持夜谁..但是在胜负未分之前, 我支持楼上的 FrameSniper(§好好学习 天天向上§) 老兄的..呵.
      

  11.   

    哈哈,看来对于字符串的概念不只我一个人混淆啊,不过没关系,有这么多大虾热心相助,大家一定都会清楚的,呵呵,我后来用rightstr(s,1)=#0就解决了,不知道对不对啊
      

  12.   

    如果字符串是AnsiString,那它的最后一位肯定不是null
    除非你自己
    var s:string;
      s:='12345678';
    S[Length(s)]=#0;
      

  13.   

    To L_Lei,Zjqyb  可以!其实方法有很多,但这里存在一个问题,就是默认字符串在Delphi中的存储结构是什么样子的,以及我们平时接触的函数对这种结构的操作是如何进行的!我想单单用一个RightStr函数是看不出来上面那两个问题的答案吧!你说呢?
      

  14.   

    不知道楼主要做什么,
    ansistring和pchar的区别大家都知道,为什么object pascal要弄一个ansistring,而不是直接使用c/c++里的pchar(当然c/c++里不叫pchar,而叫char*)?就是为方便使用,为什么非要给ansistring后面加一个0呢?
    世界变了,人也变了。
      

  15.   

    不知道楼主要做什么,
    ansistring和pchar的区别大家都知道,为什么object pascal要弄一个ansistring,而不是直接使用c/c++里的pchar(当然c/c++里不叫pchar,而叫char*)?就是为方便使用,为什么非要给ansistring后面加一个0呢?
    世界变了,人也变了。
      

  16.   

    我想你进入误区了。首先,你的字符串是什么类型?
    string,ansistring: 则最后一个字符是 s[Length(s)]。
    PChar: 则必须以 #0 终结,否则,将访问到其它空间。
      

  17.   

    procedure  tform1.fenjie (fjstr:string);
    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;
      

  18.   

    还有就是
    tmp_r是在这个位置定义的全局变量:var
      Form1: TForm1;
      tmp_r:string;
    implementation
      

  19.   

    不是吧,还在讨论啊,我认为没有再讨论的必要了吧?首先当{$H+}时,你申明的String肯定是AnsiString,这个时候Delphi会自动在末尾添加#0作为结束符!这点很清楚,还有什么不清楚的吗?
      

  20.   

    楼上,有个概念不太清楚,ps:=pchar(fjstr)之后,fjstr是否变成了pchar,还是只是说把fjstr的值后面加个#0赋给ps,即让ps指向fjstr的第一个字母,而fjstr本身还是string?
      

  21.   

    错,大错特错!不是因为使用PChar才把AnsiString后面加了#0,而是在编译开关{$H}打开的情况下,你申明一个String类型的变量,编译器就默认这是一个AnsiString类型,就自动在后面为你添加一个Null结束符,并且和ShortString的存储类型也不一样,而且对于AnsiString类型的字符串,每个字符是AnsiChar组成的,并且保存引用记数功能,所以对于AnsiString的操作一般来说是进行指针的拷贝,所以速度很快!比如
    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;
      

  22.   

    PChar是指针,永远都是四个字节如果在{$H+}环境下,你申明一个AnsiString变量,然后赋予值(这个时候编译器动态给这个变量分配空间),最后你用StrLen和Length返回长度,你会发现这个长度是不带Null结束符的变量程度!
      

  23.   

    StrLen(PChar) 取得的长度不包含 #0
    但 PChar 占用的空间包括这个 #0 所占的空间
      

  24.   

    StrLen(PChar) 取得的长度不包含 #0
    但 PChar 占用的空间包括这个 #0 所占的空间
      

  25.   

    To HiFlowerPChar是指针啊,指针怎么包含字符#0的空间啊?两个根本就是不相关的东西
      

  26.   

    To HiFlowerPChar是指针啊,指针怎么包含字符#0的空间啊?两个根本就是不相关的东西
      

  27.   

    TO  FrameSniper(§好好学习 天天向上§) 
      能不能举个简单的例子说明一下这些类型的关系啊,比如string,ansistring,widestring,pchar,pwidechar,不问还可以,一问现在脑子一团糟,谢谢了!
      

  28.   

    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;
      

  29.   

    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;
      

  30.   

    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;
      

  31.   

    我说得不清楚。
    我是指如果要把一个 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;
      

  32.   

    天啊,这些东西很多上面都有介绍啊!对于申明字符串,当编译指令{$H}处于+状态时,编译器默认你申明的String为AnsiString,具体存储格式和特点前面已经说了,但也不是只要处于这个状态下就一定被编译器默认为AnsiString,当你在申明的时候指定长度,那么编译器认为就是ShortString!如下:{$H+}
    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字符!好了,就这么多了,更加详细的内容网络上可以查到很多.....
      

  33.   

    To HiFlower  我是指如果要把一个 string 传给一个 PChar 类型,给 PChar 分配空间时,要比字符串长度多 1 个空间。----对于这个话我认为还是不正确,首先要明白一点,PChar只是一个字符串指针,既然是指针那么长度肯定是4个字节,我想这个无庸置疑!另外PChar中存放的地址只是堆栈上具体AnsiString字符串中偏移为0处的地址,至于偏移为负的部分分别存放的是当前AnsiString的分配空间大小,引用计数和长度(注意:分配空间大小和长度是不一样的!),从偏移为0处开始存放的才是具体的字符数组,最后加一个Null结束符。  PChar就是一个指针,只不过是稍微特殊点的指针,其内容是指向一个以Null结尾的AnsiString字串的偏移为0处的地址!仅此而已!
      

  34.   

    我想请教一下 FrameSniper大侠:
    你说AnsiString类型的结构如下:
    strAnsi = record
       nSize: Integer;
       nRef: Integer;   
       nLength: Integer;
       szBuf: array of Char;
    end;
    那请问我为什么不能跟操作结构类型一样的操作AnsiString呢?
    还用你怎么知道它的结构是这个样子的?有点不合理吧,怎么会是这样的呢?
      

  35.   

    我这里说这个结构是这样,只是用记录的形式去做个比喻,真正的结构肯定不是这个样子的。就好比RTTI中的结构也可以用记录去比喻,但RTTI真正的结构未必全部都是记录,至少是可变记录!所以这种书写方式只是为了便于理解另外,这个结构在D5和D6开发指南上都有很明确的示意图,你可以去查阅这些书籍看看!至于合理不合理我想不是我们这里要讨论的,Borland就如此设计了,你说他不合理我也没有办法,呵呵........下面是D5开发指南上关于AnsiString内存分配情况的一个示意图:----------------------------------------------------------------
    |  分配大小 |  引用计数  |  长度  |  具体字符串内容 ....  | #0 |
    ----------------------------------------------------------------
    对于以Null结尾的字符,都是动态分配空间的,而且没有255的长度限制,而我们上面所说的PChar、PAnsiChar和PWideChar都是指针,他们的内容所指向的偏移为0的地址应该都是上图从左到右第四段那里的起始地址........
      

  36.   

    你这种比喻的确让人误解了
    帮助中有这么一段
    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
    好像和你的有点出入哟
      

  37.   

    没有出入!帮助里只是忽略了分配空间部分的内存区域(我不清楚为什么这样做,但这个区域的确存在!)另外更正上面说到的一点:WideString是没有引用计数的!
      

  38.   

    同样,如果你用Length和StrLen来试着获取AnsiString的长度,可以看到并不包含Null结束符的长度!
      

  39.   

    如果AnsiString中间有#0,那把它转化成Pchar也就没有任何意义
    要把一个 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);
     
      

  40.   

    哦?莫非我理解错你们的意思了?“要把一个 string(中间没有#0) 传给一个 PChar 类型,
    给 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);
      

  41.   

    对于s:='1234';
    分配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!!!
    打字真累!!!
      

  42.   

    我认为 FrameSniper(§绕瀑游龙§) 的意思和我有所不同,他的意思可能是这样:
     pc:=PChar(s);
    这样的话,当然不需要为 PC 分配空间。
    而我的意思是把 s 的内容复制到由 PC 所指向的一块内存空间,这时,为 PC 分配空间时就要多一个 #0 的空间了。
      

  43.   

    首先我对你提出的分配空间表示怀疑,的确,帮助上是这么说,但如果你看过D5、6开发指南,上面有很明确的示意图,对于AnsiString最开始的空间存放的是实际分配空间大小,而且也是四个字节,所以首先这里的空间应该是在你的基础上加4!另外,你的回复中的话,“Borland不可能为Pchar(s)重新分配内存,也没有此必要,因为已开始已分配了Length(s)+1的空间,并且确保s[length(s)]=#0,所以中间含有#0的AnsiString其实非常危险,特别是Pchar(s)的调用肯定会出问题!!!”,我有几点想问Zjqyb:1.什么叫Borland不可能为PChar(S)分配内存?对于指针类型,我想大小为4个字节是无庸置疑的,如果这里各位还认为有什么疑问,我想就没有多大必要了!PChar(S)永远都是四个字节!而且在目前版本中Char相当与AnsiChar,至于以后版本,或许会成为WideChar。2.我到现在都不明白你那里为什么非要PChar(S)分配Length(S)+1的空间,个人认为这种分配完全没有必要!因为S在{$H+}状态下本身就是一个AnsiString!所以,楼上第三行中的话“对于最后的#0,AnsiString绝对是要分配的,否则Pchar(s)根本不可能实现!!!”----首先需要明确一点,AnsiString的特点就是以Null结束符结尾,而且这个和PChar的实现有什么关系?最后再次申明一点的是:既然讨论Ansi字符串,就应该明白这是一种字符串类型!一但申明,存储结构和特征就已经存在,而不是通过某种转换来实现的!
      

  44.   

    To HiFlower  的确,我是一直没有理解你们的意思,既然你这里已经提到复制问题,肯定是要依照你们那样做的了,先分配空间,然后复制!
      

  45.   

    ////
    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;难道这还有疑问!!!
      

  46.   

    当然指针是占用4个字节的空间
    getmem应该是给指针指定一个可操作的地址范围(内存空间)
    strcopy就应该是将具体的字符串copy到这个地址范围(内存空间)里,这个地址就是指针指向的地址所以,大家都是正确的
      

  47.   

    To zjqyb  请教一个问题,如果一个AnsiString的内容是1234,那么你认为实际给这个字串分配的空间是多少?
      

  48.   

    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;FrameSniper你如何解释?
      

  49.   

    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;你如何解释?
      

  50.   

    FrameSniper:我是按你的计算方式来的,请问另外4个字节在哪去了?
      

  51.   

    To BlueCatAnsiString类型的结构如下:
    strAnsi = record
       nSize: Integer;
       nRef: Integer;   
       nLength: Integer;
       szBuf: array of Char;
    end;这是我前面给出的结构示意,和你说的4+4+4+17+1的结果有什么区别吗?
      

  52.   

    s:='My name is delphi';//17个字节
    按你给的结构,占用4+4+4+17+1=30个字节,没错吧?我这样计算s占用空间:
    integer(pointer((integer(@s[1])-12))^); //应该没错吧?
    为什么占用了34个字节?
      

  53.   

    s:='My name is delphi';
    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
      

  54.   

    zjqyb(风清扬*任它溺水三千,我只取一瓢饮*) 有点道理,但还有一个存储s的指针,那岂不是还要加4个字节???
      

  55.   

    s:='My name is delphi';
    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前面还有一个指针,我不明白这个指针里面保存的内容是什么,因为这个结构表示的内存空间应该是在堆栈上的!
      

  56.   

    我现在想请教各位个问题:对于AnsiString类型的变量,由于其自身也是一个指针,内容是堆栈里面的一个地址,而这个地址是上面这个结构中szBuf的首地址!那么我想请问各位,如果要返回szBuf的首地址要如何写呢?
      

  57.   

    我没说szBuf前面有一个指针
    我是没搞董,为什么szBuf已经占用了17个字节,它还占有一个指针(4个字节)的空间?
    我想,既然szBuf是一个指针,那就应该占有一个4字节的空间
    那么,s(AnsiString)也是一个指针,为什么就不该再占用4字节的空间呢?
    难道s这个指针恰好和szBuf这个指针重合(就是一个地址)?这样就解释清楚了?
    所以FrameSinper给出的ansistring的结构才是正确的?help中的结构是不全的?
      

  58.   

    返回szBuf的首地址?我的代码中不是给出了吗?难道有错?@s[1]应该没错吧?
      

  59.   

    To BlueCat  Help中的结构也不能说不正确,但至少不是很全!  你的那个代码我也实验了,的确是34,和我说的有点出入,我也正在想这种出入是哪里导致的!我现在有一个疑惑,刚才请教了几个人,里面有人说我给出的那个结构里的szBuf应该也是一个指针,而且那个结构不是存放在堆栈里面的!我现在这里有点表示不同意!
      

  60.   

    FS那个说法是我给出的,但是偶要声明,偶的信息来自BCB的源码,至于DELPHI的实现细节因为没有源码,不太了解。
    贴出BCB的源码片断:  class RTL_DELPHIRETURN AnsiString
      {
    ...
      protected:
    ...
        struct StrRec {
          int allocSiz;
          int refCnt;
          int length;
        };
    ...
      private:
        // assert(offsetof(AnsiString, Data) == 0);
        char *Data;
      };
      

  61.   

    strAnsi = record
       nSize: Integer;
       nRef: Integer;  
       nLength: Integer;
       szBuf: array[0..0] of Char; 
    end;
    这个结构肯定不是在一个连续的空间上,所以szBuf仅仅是一个指针,它的值应该在另一段空间中,所以导致整个空间多了4个字节,不知道是不是这样?
      

  62.   

    补充一些:
    早年的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的实现方式。
      

  63.   

    在bcb中已经将AnsiString定义成了一个类,但delphi中AnsiString肯定不是一个类
    我想这两者的区别就大了
      

  64.   

    看看帮助中说的:A long-string variable is a pointer occupying four bytes of memory. When the variable is empty--that is, when it contains a zero-length string--the pointer is nil and the string uses no additional storage. When the variable is nonempty, it points a dynamically allocated block of memory that contains the string value. The eight bytes before the location contain a 32-bit length indicator and a 32-bit reference count. This memory is allocated on the heap, but its management is entirely automatic and requires no user code.“....This memory is allocated on the heap....”,这里的memory我想应该是指的“The eight bytes before the location contain a 32-bit length indicator and a 32-bit reference count”里面的The eight bytes和后面的location,而那个location则是指上面的a dynamically allocated block of memory that contains the string value.所以还象我上面给出的那个结构一样,指示长度和引用计数这两块和后面的实际字串内容应该是在一起的!而且他们的内存都是在堆heap上!我这样理解应该没有错误吧!(我怎么感觉我像在做考研英语阅读理解!)
      

  65.   

    好了,我刚翻了资料,不用忧郁了,我前面给出的那个结构肯定是在一个连续的内存空间上分配的!而且,结构完全就是那样!所以现在唯一的问题就是为什么得到的分配空间大小都比实际的空间大四个字节,正好是一个指针的大小。而且前面的zjqyb的那种假设szBuf前四个字节组成一个指针的看法是错误的!所以现在问题很明确了,如下:对于AnsiString长字符串,当申明一个变量的时候类似对象一样,只是在栈上分配四个字节的指针!当这个字符串不为空的时候才在堆(heap)上分配我前面给出的类似那个结构的空间!现在问题就是为什么仿照BlueCat的方法获取的空间大小比实际大小要大四个字节?----------------------------------------------------------------------请各位讨论!
      

  66.   

    “指示长度和引用计数这两块和后面的实际字串内容应该是在一起的!而且他们的内存都是在堆heap上!”的确是这样但是
    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个字节这样对否?
      

  67.   

    没有方法!对象实体空间是不存放方法成员的信息的,只放数据成员!而且Delphi中好象没有提供这样的函数去求这个空间的大小!
      

  68.   

    strAnsi = record
       nSize: Integer;
       nRef: Integer;  
       nLength: Integer;
       szBuf: array[0..0] of Char; 
       end;
    szbuf其实就是Ansistring的指针
      

  69.   

    这样理解应该也是一样
    strAnsi = record
       nSize: Integer;
       nRef: Integer;  
       nLength: Integer;
       szBuf: pChar; 
       end;
    szbuf
      

  70.   

    To Zjqyb  应该不是这个样子吧!
      

  71.   

    zjqyb(风清扬*任它溺水三千,我只取一瓢饮*) 你能不能给大家分析一下你的结论怎样从汇编里面得来的?
    现在小弟正在学汇编,请多指教,在此谢过
      

  72.   

    偶看了风兄的建议,看了一下汇编代码。基本上是这样:当新建一个String并向它赋一个串值时:首先,计算其串长度,得nLen,以前面那个17char的例子来说,就是$11(#17)
    然后,根据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了。
      

  73.   

    相关的汇编函数:@LStrFromPChar:根据一个PChar来创建一个String的Instance
    @LStrFromPCharLen:根据一个长度来创建一个String的Instance
    @NewAnsiString:根据Len创建一个新的String Instance
    @GetMem:分配内存有兴趣的可以自己在CPU Windows里看:)
      

  74.   

    我是菜鸟
    我喜欢以上大虾们的这种辩论
    能让人深入的了解Delphi底层的东西,有益我等菜鸟的健康成长
    佩服
    感谢大虾们