[Delphi] Сдвиг массива

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Kandi, 9 Aug 2012.

  1. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Добрый день всем) интересует такой момент, не могу его понять. Вот я сдвигаю массив процедурой Move, затем уменьшаю длину массива SetLength у меня всё нормально уменьшается как надо, вот только почему-то последний элемент массива после уменьшения его длины просто обнуляется. WTF?
    Code:
                  Acc := AccArr[0, 0];
                  Pass := AccArr[0, 1];
                  Finalize(AccArr[0, 0]);
                  Finalize(AccArr[0, 1]);
                  // Делаем сдвиг массива влево на 1
                  Move(AccArr[1], AccArr[0], (Length(AccArr) - 1)*SizeOf(AccArr));
                  // Уменьшаем длину массива
                  SetLength(AccArr, Length(AccArr) - 1);
    
     
  2. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    Голова не варит сегодня, но могу скачать точно что есть ошибка с SizeOf(AccArr), это не правильно, т.к. AccArr - ссылка на динамический массив, и размер равен 4 байтам. Ты копируешь ячейки данного массива и если размер ячейки не равен 4, то будут проблемы.
    Если ячейка массива - еще один динамический массив или структура содержащая динамические строки, то копировать придется его в ручную, если нет - то делаем так:
    Code:
                Acc := AccArr[0, 0];
                  Pass := AccArr[0, 1];
                  Finalize(AccArr[0, 0]);
                  Finalize(AccArr[0, 1]);
                  // Делаем сдвиг массива влево на 1
                  Move(AccArr[1], AccArr[0], High(AccArr)*SizeOf(AccArr[0]));
                  // Уменьшаем длину массива
                  SetLength(AccArr, High(AccArr));
     
    #2 Jingo Bo, 10 Aug 2012
    Last edited: 10 Aug 2012
  3. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0

    У меня динамические строки подгружаемые из файла(( ну а в ручную только последний элемент или весь массив? и как понять в ручную? есть еще вариант последнюю ячейку массива держать пустой, вроде работает. ну это бред мне кажется, хотя лучше чем копировать на мой взгляд...
     
  4. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    В ручную я имел ввиду :
    Code:
        {Сдвиг}
        for i := n to High(AccArr) - 1 do
        Begin
            SetLength(AccArr[i], High(AccArr[i+1])+1);
            for j := 0 to High(AccArr[i]) do
              AccArr[i, j] := AccArr[i+1, j];
        end;
        {Удаление последнего}
        SetLength(AccArr, High(AccArr));
    n - индек элемента, который нужно удалить.
     
  5. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Понятно, просто, если подгрузят 50 тысяч акков то боюсь будет худо) У меня вот всё норм работает если я создаю последний элемент массива пустые строки.... тогда всё сдвигается и удаляется вроде бы как надо. С помощью Move.
     
    #5 Kandi, 10 Aug 2012
    Last edited: 10 Aug 2012
  6. ADR-007

    ADR-007 Member

    Joined:
    12 Jul 2010
    Messages:
    218
    Likes Received:
    9
    Reputations:
    0
    код TList<T>

    Code:
    procedure TList<T>.DoDelete(Index: Integer; Notification: TCollectionNotification);
    var
      oldItem: T;
    begin
      if (Index < 0) or (Index >= Count) then
        raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
      oldItem := FItems[Index];
      FItems[Index] := Default(T); //это 
      Dec(FCount);
      if Index <> Count then
      begin
        System.Move(FItems[Index + 1], FItems[Index], (Count - Index) * SizeOf(T));
        FillChar(FItems[Count], SizeOf(T), 0); // и это обезательно! (не помню зачем)
      end;
      Notify(oldItem, Notification);
    end;

    И вообще: советую перейти на Delphi XE2 и TList<T> вместо масивов.

    А если нужна очередь - тогда TQueue<T>.
     
    #6 ADR-007, 10 Aug 2012
    Last edited: 10 Aug 2012
  7. altblitz

    altblitz Elder - Старейшина

    Joined:
    5 Jun 2009
    Messages:
    3,694
    Likes Received:
    3,149
    Reputations:
    236
    Code:
    // Делаем сдвиг массива влево на 1
                  Move(AccArr[1], AccArr[0], (Length(AccArr) - 1)*SizeOf(AccArr));
                  // Уменьшаем длину массива
                  SetLength(AccArr, Length(AccArr) - 1);
    ясно же - память изначалаьно не зарезевирована под массив.

    ошибочный код, без задания параметров массива с учётом переноса в другой, временный.

    правильно - задать величину оригинального массива и временный,
    для операций копирования данных.