string类型,你真的了解吗?

cjf1009 2004-09-29 05:00:23
我定义了一个记录类型:
TCommBlock = record // the Communication Block used in both parts (Server+Client)
Command,
MyUserName, // the sender of the message
acciid, // the message itself
ReceiverName: string[255]; // name of receiver
Msg:widestring;
end;

1、ReceiverName: string[255]; 是什么意思?最长是256个字节吗?我这个记录是网络中传输的,如果这样定义:ReceiverName: string;则程序会产生错误。
2、receivername字段是可能是超过1000的字符串,这样的变量怎么定义?
3、string、shortstring、AnsiString、WideString,到底有什么区别?
...全文
460 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
WGYKING 2004-10-04
  • 打赏
  • 举报
回复
这种结构是严重错误的
所谓结构
是一种简单类型
定义后地址就静态指定了

而String或类似的长字符或宽字符类型的变量
在操作时内存就会重新分配

当你将结构作为一个 VAR 型整体操作时
访问字段数据时
将按指针简单移位
无法正确定位动态分配的地址
所以会发生错误

当然
巧合的情况下
你只操作此类型的字段值一次
恰好可以操作成功
WGYKING 2004-10-04
  • 打赏
  • 举报
回复
plainsong(短歌) 那样按顺序发送
wizardqi(男巫) 那样定义定长的字段值的结构

流的方式也是一样的
var
Command,
MyUserName,
acciid,
ReceiverName,
Msg: String;

AStream: TMemoryStream;
Writer: TWriter;
begin
{
Command,
MyUserName,
acciid,
ReceiverName,
Msg: String;
给它们赋值}

AStream := TMemoryStream.Create;
Writer := TWriter.Create(AStream, 4096);
Writer.WriterString(Command);
Writer.WriterString(MyUserName);
//...Other String
Writer.FlushBuffer;

Connection.OpenWriteBuffer;
Connection.WriteStream(AStream);
Connection.CloseWriteBuffer;

FreeAndNil(Writer);
FreeAndNil(AStream);
end;


接收时创建TReader顺序读出来就可以了
cjf1009 2004-10-04
  • 打赏
  • 举报
回复
WGYKING(昵称)
老兄说的是什么意思?说的数据传输的时候吗?你给写个demo吧
WGYKING 2004-10-04
  • 打赏
  • 举报
回复
也不知真的假的

^_^
WGYKING 2004-10-04
  • 打赏
  • 举报
回复
解决方式就是:
按给定的协议顺序发送和接收
或者就打包成一个流
cjf1009 2004-10-03
  • 打赏
  • 举报
回复
widestring和string之间怎么转换?或者说需要转换吗?
一个函数,形参定义的是string,可我却传了一个widestring的值过去,可以吗?
FrameSniper 2004-10-02
  • 打赏
  • 举报
回复
老调重谈.....学习.....
todouwang 2004-10-02
  • 打赏
  • 举报
回复
...
短歌如风 2004-09-30
  • 打赏
  • 举报
回复
简单的解释,如果你熟悉C的话:
string[255]相当于char[255],而string则类似于char *(当然要复杂得多,它是自动管理内存并维护了写时复制——COW逻辑)。所以你定义为string接收方会出错——你把一个地址发到别一台机器上去访问,当然会有问题。
事实上short string并不适合于在网上传送数据,虽然传送它比较简单,但必须要把长度定义为可能的最大值,比较浪费。你应该定义为string类型。并且不应该直接传送整个record,而应该按固定的顺序传送每一个域,接收方按同样的顺序接收;在传送字符串时先传送长度,再传送内容,接收方先接收长度,然后把字符串长度设置好再接收内容。
billwillman 2004-09-30
  • 打赏
  • 举报
回复
string[255]其实是一个shortstring类型(不是指针)度为255大小,如果是string类型在默认编翻器下为Ansistring类型,Ansistring实际上是个指针你用sizeof函数可以知道它的大小为4,指针指向的区域包含四个区域:
-8 存储引用计数//目的为自动释放存储空间
-4 存储字符的长度//为了用与Length()函数
0..Length-1 存贮实际的字符
Length 零字符(NULL或#0)//为了便于和PCHAR类型转换

widestring的结构与上面类似但是没有引用计数
懒猫 2004-09-30
  • 打赏
  • 举报
回复
学习Delphi中,我也不理解string,关注此贴ing
wizardqi 2004-09-30
  • 打赏
  • 举报
回复
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Sockets, IdTCPServer, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient;

type
TForm1 = class(TForm)
Button1: TButton;
TCPC: TIdTCPClient;
TCPS: TIdTCPServer;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure TCPSExecute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;
TArticle=record
Title:String[255];
Author:String[64];
Content:array[0..1000] of Char;
end;
PArticle=^TArticle;

var
Form1: TForm1;
sd,rd:TArticle;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
sd.Title:='小故事';
sd.Author:='男巫';
sd.Content:='程序设计艺术';
TCPC.Connect;
if TCPC.Connected then
begin
TCPC.WriteBuffer(sd,SizeOf(sd));
TCPC.Disconnect;
ShowMessage(IntToStr(SizeOf(sd)));
end;
end;

procedure TForm1.TCPSExecute(AThread: TIdPeerThread);

begin
AThread.Connection.ReadBuffer(rd,SizeOf(rd));
AThread.Connection.Disconnect;
Memo1.Lines.Add(rd.Title);
Memo1.Lines.Add(rd.Author);
Memo1.Lines.Add(rd.Content);
end;

end.
cjf1009 2004-09-30
  • 打赏
  • 举报
回复
plainsong(短歌) :
这样就可以直接把他们定义成string,或者widestring,而不用指定长度了吗?
短歌如风 2004-09-30
  • 打赏
  • 举报
回复
既然你用的是Indy组件,它有一个很方便传送string的方法:WriteLn,为什么不用呢?
发送端:
IdTCPClient1.WriteLn(Commblock.Command);
IdTCPClient1.WriteLn(Commblock.MyUserName);
IdTCPClient1.WriteLn(Commblock.Msg);
IdTCPClient1.WriteLn(Commblock.ReceiverName);
IdTCPClient1.WriteLn(Commblock.acciid);
接收端:
AThread.Connection.ReadLnWait(Commblock.Command);
AThread.Connection.ReadLnWait(Commblock.MyUserName);
AThread.Connection.ReadLnWait(Commblock.Msg);
AThread.Connection.ReadLnWait(Commblock.ReceiverName);
AThread.Connection.ReadLnWait(Commblock.acciid);
你说的Demo直接传送整个record说明它的recod是一个线性结构,没有象String之类的指针类型的数据。事实上即使如此也最好分不同的域进行传送,原因一是避免传送用于字节对齐的填充数据节省网络带宽;二是向整数等类型在Indy中有专门的传送方法,不用自己考虑字节序等问题。

cjf1009 2004-09-30
  • 打赏
  • 举报
回复
这样说吧:
TCommBlock = record
Command,
MyUserName,
acciid :string[20]; 上面的变量不会太长。
ReceiverName ://长度超过1000,我本想用string。
Msg ://长度超过1000,我本想用widestring;
end;
现在是不是recevername和msg都改成array[0..1000] of char类型?

改完之后我定义的时候:
procedure TForm1.Button1Click(Sender: TObject);
var
name : array[0..1000] of char;
text : string;
i : integer;
begin
text := '中国人民1,肯一1';
for i:=0 to 1000 do
begin
name[i] :=text[i];
end;
showmessage(name);
end;
我该怎么定义?这样name显示有时会出错。如果定义成text : widestring;更是编译都过不去。
我只是不想改变初衷。
wizardqi 2004-09-30
  • 打赏
  • 举报
回复
发送和接收当然要使用同样的数据结构了(使用相同的记录结构),这样才能达成协议。
wizardqi 2004-09-30
  • 打赏
  • 举报
回复
string、shortstring、AnsiString、WideString,到底有什么区别?
-----------------------------------------------------------------------------------
String,ShortString,AnsiString用于存放8bit的ASCLL字符串,ShortString占用2-255个字节存储空间,而AnsiString占用4-2^31(2GB)个字节存储空间,当使用{H$+}编译指令时String使用AnsiString的存储长度,相反使用{$H-}时使用ShortString在存储长度.

WideString的存储长度和AnsiString相同,只不过它用于存放Unicode字符,也就是宽字符,比如汉字。
cjf1009 2004-09-30
  • 打赏
  • 举报
回复
wizardqi(男巫) :
老兄,如果定义成array[0..1000] of Char;那接收端该怎么定义?怎么使用?
cjf1009 2004-09-30
  • 打赏
  • 举报
回复
按顺序传输?可那些变量还是应该那么长啊,一个长度超过1000的字符串,该用什么表示?
我用的idtcpclient控件,只是看了一个demo,依葫芦画瓢的,不知道怎么按顺序传。
我的传输程序:
Commblock.Command := 'Send';
Commblock.MyUserName := user_name;
Commblock.Msg := Msg;
Commblock.ReceiverName := Spot;
Commblock.acciid := AcciID;
IdTCPClient1.WriteBuffer (Commblock, Sizeof (Commblock), True);

接收程序:
if not AThread.Terminated and AThread.Connection.Connected then
begin
AThread.Connection.ReadBuffer (CommBlock, SizeOf(CommBlock));
if Commblock.Command='Send' then
begin
Username := CommBlock.MyUserName;
Msg := CommBlock.Msg;
Toname := CommBlock.ReceiverName;
acciid := commblock.acciid;
end;
wizardqi 2004-09-30
  • 打赏
  • 举报
回复
承接上文:
-----------------------------------------------------------------------------
从上面的代码不难看出,没有指定长度的String是个标识(当然你可以理解为指针),它指向不在记录体内的内存区域。你测试如下的代码很容易得道答案。
TCommBlock = record // the Communication Block used in both parts (Server+Client)
Command,
MyUserName, // the sender of the message
acciid, // the message itself
ReceiverName: string[255]; // name of receiver<-----注意没有指定长度
Msg:widestring;
end;

ca,cb:TCommBlock;
ShowMessage(IntToStr(SizeOf(cb)));
cb.ReceiverName:='cjf1009(农民程序员) ( ) 信誉:97';
ShowMessage(IntToStr(SizeOf(cb)));
---------------------------------------------------------------------------------------
从上面的测试不难发现:如果要按区块传输数据,如果使用字符串需要指定长度。如果长度大于255可以使用字符数组。如 array[0..1000] of Char;

加载更多回复(4)

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧