Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.174] |
|
Сообщ.
#1
,
|
|
|
У меня есть массив где присутствует 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 Как исправить? Вот мой код: 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. |
Сообщ.
#2
,
|
|
|
Потому что Length(tmpItem) возвращает не последний индекс массива, а его длину. У тебя в цикле в последней итерации происходит выход за пределы массива со всеми вытекающими
Используй high(tmpItem) для получения максимального индекса массива. Кроме того, нахрена два цикла, приучайся сразу писать нормальный код, за плохой, будут бить по рукам. 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; |
Сообщ.
#3
,
|
|
|
Gonarh, здравствуйте я тут сделала перемешивание объектов основного массива и добавление первых пяти случайных элементов во второй массив. У меня опять получилось два цикла. Подскажите можно как-нибудь также записать в один цикл перемешивание и добавление как в предыдущем примере.
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. |
Сообщ.
#4
,
|
|
|
Нет там перемешивания, есть перезатирание. Второй массив участвует только в выводе, а третий вообще не используется.
|
Сообщ.
#5
,
|
|
|
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 ... 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; |
Сообщ.
#6
,
|
|
|
Цитата Gonarh Кроме того, нахрена два цикла, приучайся сразу писать нормальный код, за плохой, будут бить по рукам. 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 ... 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 случайных достаточно сделать так 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; 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; |