Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 record и очень динамические массивы  [new]
Tim Woo
Member

Откуда:
Сообщений: 33
Добрый день!
Имеется вот такая record:

+
type TAnswers = record
    nQ  : Integer;
    nQS : Integer;
    nM  : Integer;
    nD  : Integer;
    nnD : array of Integer;
    Keys : array of Char;
    Names : array of array of string;
    Results   : array of array of Char;
    Matrix    : array of array of Integer;
    Relevance : array of array of Integer;
    Total     : array of array of Real;
    Correct   : array of Integer;
    Diff      : array of Real;
    P         : array of Real;
    Q         : array of Real;
    PQ        : array of Real;
    PQs       : Real;
    DI        : array of Real;
    Variance  : Real;
    PKR20     : Real;
    SEM       : Real;
    AvDiff    : Real;
    AvDI      : Real;
    AvTotal   : Real;
  end;


Имеется переменная Data, которая TAnswers.

Ситуация N1 - Создание и заполнение переменной Data "с нуля".
Пользователь указывает два числа, которые позже станут Data.nQ и Data.nM.
После этого все массивы из Data должны будут создаться под размеры nQ, nM или nQ-x-nM.
Все массивы должны быть "обнуленными": числовые = 0; строки = ''; чары = #0;

Сейчас это все у меня делается вот так:
+
procedure TFormMain.SetTAnswers;
begin
  with Data do begin
      nQ := StrToInt(QN.Text);                
      nQS := nQ;                             
      nM := StrToInt(QM.Text);                             
      nD := StrToInt(DN.Text)
      SetLength(nnD, nD);
      SetLength(Keys, nQ);
      SetLength(Names, nM, 2);
      SetLength(Results, nM, nQ);
      SetLength(Matrix, nM, nQ);
      SetLength(Relevance, 5, nQ);
      SetLength(Total, nM, nD);
      SetLength(Correct, nQ);
      SetLength(Diff, nQ);
      SetLength(P, nQ);
      SetLength(Q, nQ);
      SetLength(PQ, nQ);
      SetLength(DI, nQ);  
      PQs := 0;
      Variance  := 0;
      PKR20     := 0;
      SEM       := 0;
      AvDiff    := 0;
      AvDI      := 0;
      AvTotal   := 0;
  end;
end; 


Вопросы:
Правильно ли я создаю динамические массивы в пределах указанной record?
Будут ли создаваемые массивы всегда пустыми? Или же их нужно обнулять для 100% уверенности, что при обращении к "пустому" массиву в нем будет мусор вместо пустых значений?

Ситуация N2 - Пересоздание и перезаполнение переменной Data.
Уже имеется переменная Data, где все массивы-переменные заполнены рабочими данными. Пользователь вводит новые значения, которые станут в последствии Data.nM и Data.nQ.
Вопрос:
Как правильно "убить/сбросить/обнулить" ранее созданную переменную типа record, чтобы пересоздать ее вновь, вместе с новыми размерами внутренних динамических массивов с нулевыми значениями?
27 дек 18, 16:30    [21774968]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
RWolf
Member

Откуда: Казань
Сообщений: 400
Документация
Existing characters in the string or elements in the array are preserved, but the content of newly allocated space is undefined.

т.е. новые элементы нужно обнулять.
27 дек 18, 16:36    [21774975]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
RWolf
Member

Откуда: Казань
Сообщений: 400
Tim Woo
Вопрос:
Как правильно "убить/сбросить/обнулить" ранее созданную переменную типа record, чтобы пересоздать ее вновь, вместе с новыми размерами внутренних динамических массивов с нулевыми значениями?

Finalize()
27 дек 18, 16:38    [21774978]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
rgreat
Member

Откуда:
Сообщений: 4625
Data:=Default(TAnswers);
27 дек 18, 16:52    [21774992]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10689
Tim Woo
Правильно ли я создаю динамические массивы в пределах указанной record?
Да
Tim Woo
Будут ли создаваемые массивы всегда пустыми?
Нет. Там будет мусор
Tim Woo
Как правильно "убить/сбросить/обнулить" ранее созданную переменную типа record, чтобы пересоздать ее вновь,
Незачем. Просто установите новые значения
27 дек 18, 17:12    [21775022]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3167
_Vasilisk_
Нет. Там будет мусор

Динамические массивы всегда обнуляются.
27 дек 18, 17:22    [21775029]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
rgreat
Member

Откуда:
Сообщений: 4625
Сказал же уже: Data:=Default(TAnswers);

Это полностью обнулит рекорд.
27 дек 18, 17:32    [21775047]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10689
Kazantsev Alexey
Динамические массивы всегда обнуляются.
Только для managed типов
+
procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: NativeInt; lengthVec: PNativeint);
var
  i,j: NativeInt;
  newLength, oldLength, minLength: NativeInt;
  elSize: NativeInt;
  neededSize: NativeInt;
  p, pp: Pointer;
begin
  p := a;

  // Fetch the new length of the array in this dimension, and the old length
  newLength := 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(PByte(p), SizeOf(TDynArrayRec));
    oldLength := PDynArrayRec(p).Length;
  end;

  // Calculate the needed size of the heap object
  Inc(PByte(typeInfo), 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(TDynArrayRec));
  if neededSize < 0 then
    Error(reRangeError);

  // If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy
  if (p = nil) or (PDynArrayRec(p).RefCnt = 1) then
  begin
    pp := p;
{$IF not Defined(WEAKREF)}
    if (newLength < oldLength) and (typeInfo <> nil) then
      FinalizeArray(PByte(p) + SizeOf(TDynArrayRec) + newLength*elSize, typeInfo, oldLength - newLength);
{$ELSE}
    if typeInfo <> nil then
    begin
      if newLength < oldLength then
        minLength := newLength
      else
        minLength := oldLength;
      GetMem(pp, neededSize);
      FillChar((PByte(pp) + SizeOf(TDynArrayRec))^, minLength * elSize, 0);
      if p <> nil then
      begin
        CopyArray(PByte(pp) + SizeOf(TDynArrayRec), a, typeInfo, minLength);
        FinalizeArray(PByte(p) + SizeOf(TDynArrayRec), typeInfo, oldLength);
        FreeMem(p);
      end;
    end else
{$ENDIF}
      ReallocMem(pp, neededSize);
    p := pp;
  end
  else
  begin
    Dec(PDynArrayRec(p).RefCnt);
    GetMem(p, neededSize);
    minLength := oldLength;
    if minLength > newLength then
      minLength := newLength;
    if typeInfo <> nil then
    begin
      FillChar((PByte(p) + SizeOf(TDynArrayRec))^, minLength*elSize, 0);
      CopyArray(PByte(p) + SizeOf(TDynArrayRec), a, typeInfo, minLength)
    end
    else
      Move(PByte(a)^, (PByte(p) + SizeOf(TDynArrayRec))^, minLength*elSize);
  end;

  // The heap object will now have a ref count of 1 and the new length
  PDynArrayRec(p).RefCnt := 1;
  PDynArrayRec(p).Length := newLength;
  Inc(PByte(p), SizeOf(TDynArrayRec));

  // Set the new memory to all zero bits
  if newLength > oldLength then
    FillChar((PByte(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);

  // Take care of the inner dimensions, if any
  if dimCnt > 1 then
  begin
    Inc(lengthVec);
    Dec(dimCnt);
    i := 0;
    try
      while i < newLength do
        begin
          DynArraySetLength(PPointerArray(p)[i], typeInfo, dimCnt, lengthVec);
          Inc(i);
        end;
    except
	  // Free arrays on exception
	  for j := 0 to i  do
		DynArrayClear(PPointerArray(p)[j],typeInfo);
	  DynArrayClear(p,typeinfo);
	  raise;
    end;
  end;
  a := p;
end;
27 дек 18, 17:46    [21775077]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10689
rgreat
Это полностью обнулит рекорд.
Ему не нужно обнулять. Ему нужно перезаписать и он интересуется, нужно ли вызывать какой-нибудь деструктор
27 дек 18, 17:47    [21775078]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
rgreat
Member

Откуда:
Сообщений: 4625
_Vasilisk_
Ему не нужно обнулять. Ему нужно перезаписать
Для рекорда это одно и тоже.
27 дек 18, 17:59    [21775088]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10689
rgreat
Для рекорда это одно и тоже.
Так зачем вначале обнулять, чтобы потом переписывать? Не проще ли сразу переписать?
27 дек 18, 18:01    [21775090]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3167
_Vasilisk_
Только для managed типов

Для всех:
http://docwiki.embarcadero.com/Libraries/Rio/en/System.SetLength
For a dynamic array variable, SetLength reallocates the array referenced by S to the given length. Existing elements in the array are preserved and newly allocated space is set to 0 or nil. For multidimensional dynamic arrays, SetLength may take more than one-length parameter (up to the number of array dimensions). Each parameter specifies the number of elements along a particular dimension.
27 дек 18, 18:13    [21775103]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
Tim Woo
Member

Откуда:
Сообщений: 33
Так. Для второй проблемы решил использовать
Data:=Default(TAnswers);
Чтоб уж наверняка.

По поводу "обнулений" - получается что все таки будет забит нулями?
А то из всего диалога не особо понятно :)
27 дек 18, 18:53    [21775143]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
rgreat
Member

Откуда:
Сообщений: 4625
_Vasilisk_
rgreat
Для рекорда это одно и тоже.
Так зачем вначале обнулять, чтобы потом переписывать? Не проще ли сразу переписать?
Так лаконичней.
27 дек 18, 19:12    [21775156]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 10689
Kazantsev Alexey
Для всех:
Таки да. Недоглядел
_Vasilisk_
  // Set the new memory to all zero bits
  if newLength > oldLength then
    FillChar((PByte(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);


Tim Woo
По поводу "обнулений" - получается что все таки будет забит нулями?
Получается, что будет. В Delphi 2007 уже обнуление есть
27 дек 18, 19:20    [21775169]     Ответить | Цитировать Сообщить модератору
 Re: record и очень динамические массивы  [new]
Beltar
Member

Откуда:
Сообщений: 165
Динамический массив - это ссылочный тип. => В каждой структуре отдельно выделяй память и очищай или как-то явно инициализируй.
28 дек 18, 09:30    [21775446]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить