Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Delphi: Общие вопросы > Выдает сообщение об ошибках как исправить?


Автор: Katerina1993 09.06.22, 06:37
У меня есть массив где присутствует 20 элементов. У некоторых значения empty. Я создаю новый массив куда заносятся элементы из старого массива за исключением empty.

Допустим новый массив будет называться tmpItem. Формирования нового массива будет срабатывать при нажатии кнопки Button1, чтобы вывести результат и посмотреть содержимое tmpItem я использую Memo1 и Button2.

Код работает записываются и выводятся данные как надо, но я столкнулась с такой проблемой как ошибки. Вот что происходит при записи и чтении массива.
Button1 – запись массива tmpItem.
Цитата
Access violation at address 00403EA8 in module 'Project2.exe'. White of address 00406ACB.

Button2 – чтение массива tmpItem.
Цитата
Access violation at address 00403E88 in module 'Project2.exe'. Read of address 00000046

Как исправить?

Вот мой код:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
     
    var
     
      Form1: TForm1;
      Item1: Array[0..19] of String = ('Thread','empty','Stick','Doorknob','Loupe','empty','Ring',
      'Crown','Vase','empty','Book','empty','Salver','empty','Handbell','Cigarcase','Lantern','Card','Candy',
      'Whisk');
      tmpItem:Array of String;
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    var i,j,k,jj:Integer;
    begin
    j:=0;
    for i:=0 to Length(Item1) do
    begin
     if Item1[i]<>'empty' then
     begin
      j:=j+1;
     
     end;
    end;
    setLength(tmpItem, j-1);
     
    //ShowMessage(IntToStr(Length(Item1)));
    //ShowMessage(IntToStr(Length(tmpItem)));
     
    jj:=0;
    for k:=0 to Length(Item1) do
    begin
      if Item1[k]<>'empty' then
      begin
        tmpItem[jj]:=Item1[k];
        jj:=jj+1;
      end;
     
    end;
     
     
     
    end;
     
    procedure TForm1.Button2Click(Sender: TObject);
    var i:Integer;
    begin
    Memo1.Clear;
    for i:=0 to Length(tmpItem) do
    begin
      Memo1.Lines.Add(tmpItem[i])
    end;
    end;
     
    end.

Автор: Gonarh 09.06.22, 17:53
Потому что Length(tmpItem) возвращает не последний индекс массива, а его длину. У тебя в цикле в последней итерации происходит выход за пределы массива со всеми вытекающими
Используй high(tmpItem) для получения максимального индекса массива. Кроме того, нахрена два цикла, приучайся сразу писать нормальный код, за плохой, будут бить по рукам.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var i,j:Integer;
    begin
      j:=1;
      for i:=low(Item1) to high(Item1) do
        if Item1[i]<>'empty' then begin
          setLength(tmpItem, j);
          tmpItem[j-1]:=Item1[i];
          inc(j);
        end;
    end;
     
    procedure TForm1.Button2Click(Sender: TObject);
    var i:Integer;
    begin
      Memo1.Clear;
      for i:=low(tmpItem) to high(tmpItem) do Memo1.Lines.Add(tmpItem[i]);
    end;

Автор: Katerina1993 10.06.22, 11:06
Gonarh, здравствуйте я тут сделала перемешивание объектов основного массива и добавление первых пяти случайных элементов во второй массив. У меня опять получилось два цикла. Подскажите можно как-нибудь также записать в один цикл перемешивание и добавление как в предыдущем примере.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Math;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
     
    var
      Form1: TForm1;
      slot1:Array of String;
      Item1: Array[0..19] of String = ('Thread','Goblet','Stick','Doorknob','Loupe','Statuette','Ring',
      'Crown','Vase','Gripsack','Book','Glove','Salver','Brush','Handbell','Cigarcase','Lantern','Card','Candy',
      'Whisk');
      
      arr:Array of String;
    implementation
     
    {$R *.dfm}
       //Шпаргалка
    // до ближайшего большего целого:
    //A := Ceil(15.15); // A = 16
    //В := Ceil(15.95); // В = 16
     
    // до ближайшего меньшего целого:
    //A := Floor(15.15); // A = 15
    //В := Floor(15.95); // В = 15
     
    // по математическим правилам до ближайшего целого:
    //A := Round(15.15); // A = 15
    //B := Round(15.95); // B = 16
    //C := Round(15.5); // C = 16
    //D := Round(15.4999); // D = 15
     
    // отбрасывание дробной части
    //A := Trunc(15.15); // A = 15
    //В := Trunc(15.95); // В = 15
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
     i, j,k: Integer;
      s: string;
    begin
      SetLength(slot1, 5);
      
      Memo1.Clear;
      for i := High(Item1) downto 0 do
      begin
        j := Random(i + 1);
        s := Item1[i];
        Item1[i] := Item1[j];
        Item1[j] := s;
        
      end;
     
      for k:=0 to High(slot1) do
      begin
         slot1[k]:=Item1[k];
         Memo1.Lines.Add(slot1[k])
      end;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
    Randomize;
    end;
     
    end.

Автор: Gonarh 10.06.22, 11:48
Нет там перемешивания, есть перезатирание. Второй массив участвует только в выводе, а третий вообще не используется.

Автор: RusSun 15.06.22, 05:32
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i,j: Integer;
      e1,e2: Integer; //for each index
      s: string; //bufstr
    begin
      SetLength(slot1, 5);
     
      j:=1;
     
      Memo1.Clear;
     
      for i := High(Item1) downto 0 do
      begin
      e1:=random(High(Item1)+1);  //random number in group 0..19
      e2:=random(High(Item1)+1);  //random number in group 0..19
     
        s := Item1[e1];
        Item1[e1] := Item1[e2];
        Item1[e2] := s;
     
       if j in [1..5] then
                    begin
       slot1[j-1]:=Item1[i];  //Get current Item
       Memo1.Lines.Add( intTostr(j)+') '+Item1[i])  //Add to memo1 "to see it"
                    end;
       inc(j);
      end;
     
     
    end;


May be like this ...

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
     i, j,k: Integer;
      s: string;
    begin
      SetLength(slot1, 5);
     
      Memo1.Clear;
      k:=-1;
      for i := High(Item1) downto 0 do
      begin
        j := Random(i + 1);
        s := Item1[i];
        Item1[i] := Item1[j];
        Item1[j] := s;
        inc(k);
        slot1[k]:=Item1[k];
        Memo1.Lines.Add(slot1[k]);
        if k = 4  then break
      end;
     
    end;

:D

Автор: macomics 15.06.22, 12:30
Цитата Gonarh
Кроме того, нахрена два цикла, приучайся сразу писать нормальный код, за плохой, будут бить по рукам.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i,j:Integer;
    begin
    // Циклическое изменение длины массива тоже не лучший вариант кода, порождающий не нужное
    // большое количество копирований элементов массива в массив большей длины
      SetLength(tmpItem, Length(Item1)); // Предполагаем, что нет в Item1 элементов empty
      j:=Low(tmpItem); // Для простоты работы с индексами стоит использовать Low и High
      for i:=Low(Item1) to High(Item1) do
        if Item1[i]<>'empty' then
        begin
          tmpItem[j] := Item1[i];
          inc(j);
        end;
    // Теперь уменьшим массив до нужного размера. Эта операция не должна породить операцию копирования
    // Усечение блока до меньшего размера не требует копирования элементов в новый блок
    // Даже если в реализации Delphi копирование элементов и будет, то они не будут выполняться циклически
      SetLength(tmpItem, j - Low(tmpItem) + 1);
    // Немного математики: x: array [-5 .. 4] of ee;
    //  e0 e1 e2 e3 e4 e5 e6 e7 e8 e9
    //  -5 -4 -3 -2 -1  0  1  2  3  4
    //  Low(x)                      j -> 4 - (-5) + 1 = 10
    end;

Цитата RusSun
May be like this ...
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
      for i := High(Item1) downto 0 do
      begin
        j := Random(i + 1);
        s := Item1[i];
        Item1[i] := Item1[j];
        Item1[j] := s;
        inc(k);
        slot1[k]:=Item1[k]; // Необходимо добавить первые 5, а если при i = 4 функция Random(i + 1) вернет значение 2
        Memo1.Lines.Add(slot1[k]);
        if k = 4  then break
      end;
    end;

Katerina1993: Для выбора 5 случайных достаточно сделать так
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i, j: Integer;
    begin
      Memo1.Clear;
      SetLength(slot1, 5);
      j := Length(Item1);
      for i := Low(Slot1) to High(Slot1) do
      begin
        Slot1[i] := Item1[Random(j - Low(Item1)) + Low(Item1)];
        Memo1.Lines.Add(Slot[i]);
      end;
    end;
Для выбора 5 случайных без повторений
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i, j, k, l, m: Integer;
    begin
      Memo1.Clear;
      SetLength(slot1, 5);
      j := Length(Item1);
    // Это преобразование нужно для того случая, когда Low(Item1) <> Low(Slot1)
    // Оно добавлено для демонстрации и в конечном итоге может быть убрано
    // Но! Массив Item1 вы задаете константно и индексы в нем могут отличаться от
    // индексов в динамическом массиве, хотя индексы в динамическом массиве
    // всегда находятся в диапазоне [0 .. Length - 1].
    // В общем виде переход от диапазона индексов [A .. B] к диапазону [C .. D]
    // показан в этом примере. Т.к. у динамического массива Low(Slot1) = 0, то
    // как минимум это значение можно убрать.
      l := Low(Item1) + Low(Slot1);
      m := Low(Item1) - Low(Slot1);
      for i := Low(Slot1) to High(Slot1) do
      begin
        k := Random(j - i - l) + l; // Выбор значения из диапазона [Low(Item1) + i .. Length(Item1) - 1]
        Slot1[i] := Item1[i + k]; // Переставляем это значение в начало массива Item1[i] и сохраняем его в Slot1[i]
        Item1[i + k + m] := Item1[i + m]; // На следующем проходе цикла это значение не будет затронуто
        Item1[i + m] := Slot1[i];
        Memo1.Lines.Add(Slot[i]); // Его сразу можно добавить в Memo1
      end;
    end;

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)