读书人

SetLength的用法有关问题

发布时间: 2013-04-20 19:43:01 作者: rapoo

SetLength的用法问题
问题是这样的,我的一个网络应用程序,需要从服务器端保存用户列表,于是我声明了一个动态数组来保存用户 列表
有用户登录时,就添加一个,有用户下线时就删除一个


TUser=record
UserName:string[20];
Context:TIdContext;
LastTick: Cardinal; //最后一次时钟节拍
end;

OnlineUser:array of TUser;

//添加用户
procedure AddUser(UserData:TUser);
begin
cs.Enter;
//Memo1.Lines.Add('添加用户');
//ShowOnlineUser;
try
try
if High(OnlineUser)=-1 then
SetLength(OnlineUser,2) //第2个参数应该写1或2?
else
SetLength(OnlineUser,High(OnlineUser)+2); //此处+1还是+2?
OnlineUser[High(OnlineUser)]:=UserData;
//SDIForm.WriteLog('添加到在线用户成功');
except
on e:Exception do
SDIForm.WriteLog('添加在线用户失败:'+e.Message)
end;
//ShowOnlineUser;
finally
cs.Leave;
end;
end;

procedure DelUser(UserData:string);
var i:integer;
begin
cs.Enter;
//Memo1.Lines.Add('删除用户');
//ShowOnlineUser;
try
try
for I := 0 to High(OnlineUser) do begin
if OnlineUser[i].UserName=UserData then begin
OnlineUser[i].Context.Connection.Disconnect;
OnlineUser[i]:=OnlineUser[High(OnlineUser)];
SetLength(OnlineUser,High(OnlineUser)-1);
Break;
end;
end;
//SDIForm.WriteLog('删除在线用户成功');
except
on e:Exception do
SDIForm.WriteLog('删除在线用户失败:'+e.Message);
end;
//ShowOnlineUser;
finally
cs.Leave;
end;
end;
//按现在的写法,在调用
for i:=0 to high(OnlineUser) do
onlineuser[i].connection.iohandler.write....//方法时提示越界,应该就是这面那地方的原因

//另外显示用户数据时,假设一个用户在线,总是显示
//0:
//1:user_a
//所以数组元素0应该是空的,所以越办,上面那个设置数组长度应该如何写呢?
procedure ShowOnlineUser;
var i:Integer;
begin
try
cs.Enter;
Memo1.Lines.Add('--------online user--------');
Memo1.Lines.Add('online user length:'+IntToStr(Length(OnlineUser)));
try
for I := 0 to High(OnlineUser) do begin
Memo1.Lines.Add(IntToStr(i)+':'+onlineuser[i].UserName);
end;
except
on e:Exception do
ShowMsg('获得在线列表失败:'+e.Message);


end;
Memo1.Lines.Add('-------------------------');
finally
cs.Leave;
end;
end;


[解决办法]
if High(OnlineUser)=-1 then
SetLength(OnlineUser,2) //第2个参数应该写1或2?
else
SetLength(OnlineUser,High(OnlineUser)+2); //此处+1还是+2?
OnlineUser[High(OnlineUser)]:=UserData;

改成下面2句就可以了

SetLength(OnLineUser, Length(OnLineUser) + 1);
OnlineUser[High(OnlineUser)]:=UserData;



[解决办法]
第二个参数是长度,+1表示增加一个该类型的长度,如果是int就增加4字节,如果是char就是1字节,如果是你自己的类型,就是该类型的长度
[解决办法]
单就保存连接列表来说,用TList系列的吧,效率比数组好
PUser = ^TUser;
TUser=record
UserName:string[20];
Context:TIdContext;
LastTick: Cardinal; //最后一次时钟节拍
end;

ConnectList : TList;
//需要初始化...
//添加用户
procedure AddUser(UserData:TUser);
var
P : PUser;
begin
cs.Enter;
New(P);
P^ := UserData;
ConnectList.Add(P);//增加就完成了
....
end;

procedure DelUser(UserData:string);
begin
cs.Enter;
for i:=0 to ConnectList.Count-1 do begin
if PUser(ConnectList.Items[i]).UserName=UserData then begin
Dispose(PUser(ConnectList.Items[i]));
ConnectList.Delete(i);
Break;
end;
end;
...
end;

不过我有点没搞明白,连接断开的时候,你怎么得到UserName的?难道先查连接表?
既然是先查了连接表,为什么不在直接根据断开是的条件删除连接呢?这样就只需要一次循环,一个Lock
[解决办法]
说重点吧.. . 对于一个动态数组

Tarr: array of string;

默认情况下 Tarr 长度是0
High(Tarr)等于-1;

这时想增加一条, SetLength(Tarr,1);
这里 High(Tarr) 等于0;
当然最好是用 SetLength(Tarr,High(Tarr)+2); //这样写就可以在任何情况下增加一条数据

对于High(Tarr)来说是从0开始的... 所以每新增一条数据, 重设长度为 High(Tarr)+1+1..

如果要删去一条数据.. SetLength(Tarr,High(Tarr));
这样就删除了最后一条数据
如果要册是不是最后一条, 就先把最后一条数据,保存到你要删掉的那条数据的位置, 再执行SetLength操作


如果要清除数组内容, 就用 SetLength(Tarr,0); 这时就清空了数据,,并从内存中释放数组信息

读书人网 >.NET

热点推荐