首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

SetLength的用法有关问题

2013-04-20 
SetLength的用法问题问题是这样的,我的一个网络应用程序,需要从服务器端保存用户列表,于是我声明了一个动

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);  这时就清空了数据,,并从内存中释放数组信息

热点排行