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

解决方案 »

  1.   

    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;
      

  2.   

    第二个参数是长度,+1表示增加一个该类型的长度,如果是int就增加4字节,如果是char就是1字节,如果是你自己的类型,就是该类型的长度
      

  3.   

     SetLength(OnlineUser,Length(OnlineUser)-1) ;//但是你这里应该具体删除谁下线吧 ?
      

  4.   

    单就保存连接列表来说,用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
      

  5.   

    说重点吧.. . 对于一个动态数组  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);  这时就清空了数据,,并从内存中释放数组信息