![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Глюк в динамическом массиве Delphi [D2]
AlexA © (2012-12-14 15:05:00)Есть структура
PR = record // Структура массива родителя
N: Integer; // Номер
I_: Integer; // Вход
OU_: Integer; // Выход
S_: Integer; // Старт
F_: Integer; // Финиш
C_: Integer; // Счетчик ссылок
end;
Массив
ContPar = record
Tpr: array of PR; // Массив родителей
Код
RDN_B:=2; integer
RDK_A:=1; integer
G1.Tpr[RDK_A].OU_:=RDN_B;
В после последней строчки в массиве G1.Tpr в строчке 0 появляется данные из строчки 1, а значение RDN_B записывается в строчку 1 как и должно быть, при записи в строчку 2 и далее такого нет
Тут скриншот таблицы http://89166974791.webasyst.net/DD/2...B_KEY=QUMxNjQ4
Видно в 0 строке цифры, а записывали в 1 строку, причем только в одну ячейку 1,О = 2. А в строке 0 появились 0,F=5 0,C=1
Как с этим бороться то?
AlexA (2012-12-16 21:34:00) [1]Вот мил человек натолкнул на мысль!!!
Проверил, действительно нашелся таки момент. Исправил тестим, пока все гладко
Sapersky (2012-12-16 21:11:00) [2]"Лезет" в смысле пишет не в ту область.
Банальный выход индекса за границы может дать невероятно экзотические глюки. Будешь думать на всё что угодно, вплоть до аппаратных проблем. Сам как-то несколько дней провозился.
В общем, включай Range Check.
AlexA (2012-12-16 20:33:00) [3]Код то лезет, но как такое может быть. В область памяти занятую динамическим массивом лезет код..?))
Sapersky (2012-12-16 18:47:00) [4]Range Check для начала (автору пояснение - в настройках компилятора).
Правда, на старых Delphi ([D2] в заголовке - это серьёзно?) оно не всегда работает, если record размером больше 8 байт, то вроде бы нет.
Игорь Шевченко (2012-12-16 18:44:00) [5]memproof, fastmm
Styx (2012-12-16 17:00:00) [6]
> Ничего не могу понять, что это?
А это то, что у Вас какой-то код совсем в другом месте лезет не туда, куда ему надо...
AlexA (2012-12-16 16:12:00) [7]Вот новые подробности!
Назначаю размер массиву
заполняю его нулями в цикле
Запускаю процедуру
ставлю условие на проверку значения из массива вне заданного диапазона (оно не может быть более чем известная переменная)
В итоге вылазит несколько ячеек с мусором
И это стабильно.
Сделал вместо массива чтение запись в StringGrid и глюк пропал!!!!!.
Вывод: динаимческий двумерный массив после установки его размера и обнуления может содержать мусор, и этот мусор появляется при попытке чтения/записи
И еще хохма, вынес фрагмент на котором проявлялся глюк из процедуры
в вызывающую процедуру и значение записалось правильно!!!!))
Даже было замечено что вставка по ходу программы фрагмента для вывода информации типа:
Memo1.Lines.Add(inttostr(BI.N)+'|'+inttostr(zveno));
приводит к тому что другой код работает иначе....
Ничего не могу понять, что это?
O'ShinW (2012-12-16 10:48:00) [8]тогда вариант [13]
ContPar не record, а class.
KilkennyCat (2012-12-15 23:54:00) [9]это вряд ли, было только пиво. скорее всего, я что-то не так запомнил.
Игорь Шевченко (2012-12-15 23:45:00) [10]
> и вроде тогда кто-то высказал, что в делфи возможен мусор,
> в си (того же борланда) гарантированно нулится.
Это спьяну
KilkennyCat (2012-12-15 22:09:00) [11]И вот еще помнится, что как-то на встрече в москве спорили об этом, и вроде тогда кто-то высказал, что в делфи возможен мусор, в си (того же борланда) гарантированно нулится.
KilkennyCat (2012-12-15 21:54:00) [12]тож самое...
но мусор был. хоть убей :)
begin...end (2012-12-15 21:25:00) [13]> KilkennyCat © (15.12.12 21:19) [24]
procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: Longint; lengthVec: PLongint);
var
i: Integer;
newLength, oldLength, minLength: Longint;
elSize: Longint;
neededSize: Longint;
p, pp: Pointer;
begin
p := a;
// Fetch the new length of the array in this dimension, and the old length
newLength := PLongint(lengthVec)^;
if newLength <= 0 then
begin
if newLength < 0 then
Error(reRangeError);
DynArrayClear(a, typeInfo);
exit;
end;
oldLength := 0;
if p <> nil then
begin
Dec(PLongint(p));
oldLength := PLongint(p)^;
Dec(PLongint(p));
end;
// Calculate the needed size of the heap object
Inc(PChar(typeInfo), Length(PDynArrayTypeInfo(typeInfo).name));
elSize := PDynArrayTypeInfo(typeInfo).elSize;
if PDynArrayTypeInfo(typeInfo).elType <> nil then
typeInfo := PDynArrayTypeInfo(typeInfo).elType^
else
typeInfo := nil;
neededSize := newLength*elSize;
if neededSize div newLength <> elSize then
Error(reRangeError);
Inc(neededSize, Sizeof(Longint)*2);
// If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy
if (p = nil) or (PLongint(p)^ = 1) then
begin
pp := p;
if (newLength < oldLength) and (typeInfo <> nil) then
FinalizeArray(PChar(p) + Sizeof(Longint)*2 + newLength*elSize, typeInfo, oldLength - newLength);
ReallocMem(pp, neededSize);
p := pp;
end
else
begin
Dec(PLongint(p)^);
GetMem(p, neededSize);
minLength := oldLength;
if minLength > newLength then
minLength := newLength;
if typeInfo <> nil then
begin
FillChar((PChar(p) + Sizeof(Longint)*2)^, minLength*elSize, 0);
CopyArray(PChar(p) + Sizeof(Longint)*2, a, typeInfo, minLength)
end
else
Move(PChar(a)^, (PChar(p) + Sizeof(Longint)*2)^, minLength*elSize);
end;
// The heap object will now have a ref count of 1 and the new length
PLongint(p)^ := 1;
Inc(PLongint(p));
PLongint(p)^ := newLength;
Inc(PLongint(p));
// Set the new memory to all zero bits
FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);
// Take care of the inner dimensions, if any
if dimCnt > 1 then
begin
Inc(lengthVec);
Dec(dimCnt);
for i := 0 to newLength-1 do
DynArraySetLength(PPointerArray(p)[i], typeInfo, dimCnt, lengthVec);
end;
a := p;
end
KilkennyCat (2012-12-15 21:19:00) [14]
> begin...end © (15.12.12 20:54) [23]
не путаю. DynArraySetLength я в 7-ой вообще не помню (точнее, я не знал тогда, есть сие вообще или нет). SetLength делает инициализацию лишь в определенных случаях. Автор использует последнюю.
begin...end (2012-12-15 20:54:00) [15]> KilkennyCat © (15.12.12 20:15) [22]
> у меня был мусор в D7.
Ничего не путаете? В D7-версии DynArraySetLength новый участок памяти, выделенный под динамический массив, fillchar'ится нулями.
KilkennyCat (2012-12-15 20:15:00) [16]у меня был мусор в D7.
в XE2 используется DynArraySetLength , которая в свою очередь вызывает:
...
if newLength <= 0 then
begin
if newLength < 0 then
Error(reRangeError);
DynArrayClear(a, typeInfo);
exit;
end;
...
begin...end (2012-12-15 19:42:00) [17]> KilkennyCat © (15.12.12 19:35) [20]
В необходимости. В D7 при расширении такого массива новые элементы обнулятся сами. Как с этим в новых версиях - не в курсе.
KilkennyCat (2012-12-15 19:35:00) [18]
> begin...end © (15.12.12 19:22) [18]
не уверен, что так обнуляют, или в необходимости?
begin...end (2012-12-15 19:27:00) [19]Хотя в отношении именно XE2 не уверен, сорри.
begin...end (2012-12-15 19:22:00) [20]> KilkennyCat © (14.12.12 16:24) [11]
> смотри [9]
Это вряд ли.