Работа с памятью

Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду

Ответить
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

Интересная задачка:

Дано: В памяти по адресу Buf находится массив данных состоящий из ItemCount элементов по ItemLength штук размером SizeOf(LongWord) (4 байта)

все значения _не_константы_ и вычисляются в ходе работы программы.

1. Как задать массив Array[ItemCount, ItemNumber] of LongWord чтобы удобно получать эти значения
С уважением, Lost Angel...
Vovik
Сообщения: 18
Зарегистрирован: 05 янв 2005, 14:39
Откуда: Киев

Что то типа:
type MyMas = array[1..ItemCount,1..ItemNumber] of LongWord;
SMas = ^MyMas;
....
var mas : SMas;
...
mas:=buf;

Но если ItemCount и ItemNumber могут изменятся (не константы) то, так конечно не получится. Тогда проще объявить одномерный массив размером ItemCount*ItemNumber и к элементу a[i,j] обращатся как к a[(i-1)*ItemNumber+j]
С уважением
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

вышел из положения немного подругому :)

Не очень красиво, конечно с памятью получилось... но куда деваться... :) )) особенно [0..1023] :)

Если кому интересно: модуль чтения файлов базы данных *.dbc Blizard'а
(телепортер писал для World of Warcraft)

Код: Выделить всё

unit DBC;
interface
uses
  Classes, SysUtils, Dialogs;
type
  TDBCHeader = packed record
    FileType: array[0..3] of char;
    ItemCount: LongWord;
    ItemLength: LongWord;
    Data: array[0..1] of LongWord
  end;
  TDBCData = packed record
    Data: array[0..1023] of LongWord;
  end;
Const
  OffsetBegin = 0;
  OffsetData = OffsetBegin + SizeOf(TDBCHeader);
type
  TFileDBC = class(TObject)
  private
    MemBuff: TMemoryStream;
    FFileName: TFileName;
    FLastError: Cardinal;
    FHeader: TDBCHeader;
    function GetData(i: Integer): TDBCData;
    procedure LoadDescription;
  public
    Descript: TStringList;
    constructor Create(AFileName: TFileName);
    destructor Destroy; override;
    property FileName: TFileName read FFileName;
    property LastError: Cardinal read FLastError;
    property Data[index: Integer]: TDBCData read GetData;
    property Header: TDBCHeader read FHeader;
    function GetStringByOffset(Val: LongWord): String;
  end;
implementation
constructor TFileDBC.Create(AFileName: TFileName);
Var
  FS: TFileStream;
begin
  FFileName := AFileName;
  MemBuff := TMemoryStream.Create;
  Descript := TStringList.Create;
  FS := TFileStream.Create(FileName, fmOpenRead, fmShareDenyNone);
  try
    MemBuff.CopyFrom(FS, FS.Size);
  finally
    FS.Free;
  end;
  FLastError := GetLastError;
  MemBuff.Position := OffsetBegin;
  MemBuff.ReadBuffer(FHeader, SizeOf(TDBCHeader));
  LoadDescription;
end;
procedure TFileDBC.LoadDescription;
Var S: String;
    C: Char;
begin
  MemBuff.Position := SizeOf(TDBCHeader) +
    Header.ItemCount * Header.ItemLength * 4+1;
  S := '';
  while MemBuff.Position < MemBuff.Size do
  begin
    MemBuff.ReadBuffer(C, 1);
    if C <> #00 then S := S + C
    else begin
      Descript.Add(S);
      S := '';
    end;
  end;
end;
function TFileDBC.GetStringByOffset(Val: LongWord): String;
Var
  S: String;
  C: Char;
begin
  Result := '';
  Val := Val + SizeOf(TDBCHeader) + Header.ItemCount * Header.ItemLength * 4;
  if Val < MemBuff.Size then begin
    MemBuff.Position := Val-1;
    MemBuff.ReadBuffer(C, 1);
    if C = #00 then begin
      S := '';
      MemBuff.ReadBuffer(C, 1);
      while (C <> #00) and (MemBuff.Position <= MemBuff.Size) do
      begin
        S := S + C;
        MemBuff.ReadBuffer(C, 1);
      end;
      Result := S;
    end;
  end;
end;
function TFileDBC.GetData(i: Integer): TDBCData;
begin
  MemBuff.Position := OffsetData + i * Header.ItemLength * 4;
  MemBuff.ReadBuffer(Result, Header.ItemLength*4);
end;
destructor TFileDBC.Destroy;
begin
  MemBuff.Free;
  Descript.Free;
end;
end.
С уважением, Lost Angel...
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

LAngel, есть на такой случай готовый велосипед - динамические массивы. Работать с ними можно так:

Код: Выделить всё

  type TIntArray2d = array of array of Integer;
  var ar: TIntArray2d;
  var i, j: Integer;
  SetLength(ar, ItemCount, ItemNumber);
  for i := 0 to ItemCount do
    for j := 0 to ItemNumber) do
      ar[i,j] := i*j;
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

Eugie, спасибо. именно это и искал.
С уважением, Lost Angel...
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

не получается :(
как я понял, array of array of ... Delphi строит ссылками, а не реальными данными, которые лежат в памяти.
при наведении курсора, в хинте написано:
var TDBCFile.ar: ^array of ^array of Cardinal - DBC.pas (17)
хотя объявлялось:
ar: array of array of Cardinal;
Ну и естественно, когда делаю ссылку на эту структуру и позиционирую её на область памяти, в которой лежат данные, задаю размерность, в лучшем случае в таблице мусор. в худшем - ошибка.
С уважением, Lost Angel...
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

А, понял - тебе надо как бы наложить структуру 2-мерного массива на сплошной блок памяти. Тут дин.массивы действительно не помогут. Тогда можно, как ты сделал, т.е. свой объект, в нем объявить блок памяти достаточного размера и доступаться до него через property. Кстати, property можно сделать типа 2-мерного массива: property Values[X, Y: Integer]: LongWord.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Помню как то лет десять назад в ТурбоПаскале под ДОСом я накладывал двухмерный массив из структур типа {символ,аттрибуты} на видеопамять текстового режима при помощи ключевого слова absolute, которое позволяло разместить массив в заданном месте.
2B OR NOT(2B) = FF
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

ещё, в продолжении темы.
Как, с высокой точность отличить 4 байтную структуру Cardinal (DWORD) и Single (Real32) друг от друга?

пока ничего кроме туповатого

Код: Выделить всё

          S := FormatFloat('#####.####', DF.DataFloat[Line, Pos]);
          if S = '' then S := IntToStr(DF.Data[Line, Pos]);
не придумал... :)
С уважением, Lost Angel...
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

В общем случае такого критерия нет и быть не может: оба типа используют весь битовый диапазон (single - с некоторыми оговорками). Но если имеются разумные ограничения на диапазон по каждому типу, то кое-что придумать можно. Например, если целые по модулю < 2^23 (~8000000), то в битовом соответствующем представлении single порядок будет равен 0, а single с нулевым порядком может быть либо 0, либо денормализованным маленьким числом (по модулю <~ 1^-38 ) - чем не критерий? :)

Стандартный формат Single:

Код: Выделить всё

  31|30...23|22.....0|
  |s|порядок|мантисса|
Проверить можно так:

Код: Выделить всё

  is_single := ((x shl 1) shr 24) <> 0;
Ответить