Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Работа с указателями и динамической памятью


Автор: Geniebal 16.11.2011, 08:30
Здравствуйте! 
Для передачи динамического массива между функциями хотелось бы использовать указатели. Ниже код:
Код

function func(mas: Pointer):boolean;
 var
 ...
 body_mass: Pointer;
 ...
 begin
  ...
   
   While Start>0 do
        begin
         body_mass:=nil;
         if Resident_Attribute(mas,Start,body_mass, Body_len,Attr_Len,Attr_Type) then
            begin
              ...                
              Start:=Next_Atribute(mas,start,Attr_Len); // если есть след аттр
            end
         else
           if Non_Resident_Attribute(mas,Start,body_mass,run_data_list_len,Attr_Len, Real_body_Size, Alloc_Body_Size,Attr_Type) then
              begin
                ...
                Start:=Next_Atribute(mas,start,Attr_Len);
              end;
         FreeMem(body_mass);
         end;


функции :
Код

function Resident_Attribute(mas: Pointer; Start_Attr_Byte: integer; var Body_Attr: Pointer; var Body_Len: integer; var Attr_Len: integer;var type_attr: integer): boolean;
 var
 b: string;
 Name_len, i: integer;
 begin
  ...
   Body_Attr:=GetMemory(Body_Len);
   for i := 0 to Body_Len-1 do
        PArray(Body_Attr)^[i]:=PArray(mas)^[Start_Attr_Byte+2*Name_len+24+i]; // тело атрибута
   Result:=true;
 end;

и
Код

function Non_Resident_Attribute(mas: Pointer; Start_Attr_Byte: integer; var run_data_list: Pointer; Var run_data_list_len: integer; var Attr_Len: integer; var Real_Attr_Body_Size: int64; var Alloc_Body_Atrr_size: int64;var type_attr: integer): boolean;
var
 b: string;
 i, Name_Len: integer;
begin
...
  run_data_list:=GetMemory(run_data_list_len);
 for i := 0 to run_data_list_len-1 do
     PArray(Run_data_list)^[i]:=PArray(mas)^[Start_Attr_Byte+2*Name_len+64+i]; // косячит тут!!!!
  Result:=true;

в функциях PArray это 
Код

ТArray = array of byte;
  PArray = ^TArray;


Собственно причина моего сообщения: после 2-х успешных разов завершения функции Residen_atribute (т.е. память выделяется, массив заполняется и т.д.), прохождение функции Non_Resident завершается ошибкой связаной с обращением к недоступному участку памяти! (Строка, где ывылетает эта ошибка помечена комментарием в коде) 
Мб я что то не правильно делаю?:( помогите плз, а то всю голову сломал уже...  

Автор: MetalFan 16.11.2011, 09:13
Отдели мух от котлет.
Не используй дин.массивы и ручное выделение памяти.
p.s. Либо объяви 
Код

TArray = array [0..0] of byte;

Автор: Geniebal 16.11.2011, 09:24
а как тогда передавать данные типо массива? я заранее не знаю, сколько будет данных. 
Цитата

TArray = array [0..0] of byte;

не получится

Автор: MetalFan 16.11.2011, 09:42
Цитата(Geniebal @  16.11.2011,  09:24 Найти цитируемый пост)
не получится

Почему? отключаем Range Checking и все должно работать.

Автор: Geniebal 16.11.2011, 09:59
Всмысле 
Цитата

отключаем Range Checking


если я тупо пишу TArray = array [0..0] of byte, то выдается ошибка типо - попытка обратится к элементу массива вне его диапазона.
и насколько я понимаю TArray = array [0..0] of byte это массив на 1 элемент. или я опять что то путаю?

Автор: MetalFan 16.11.2011, 10:04
мм... счас, накидаю пример.

Код

type
  PArray = ^TArray;
  TArray = array [0..0] of Byte;

procedure TForm1.btnClick(Sender: TObject);
var
  lPtr: PArray;
  i: Integer;
  lSum: Cardinal;
begin
  lPtr := GetMemory(50);
  try
    lSum := 0;
    for i := 0 to 49 do
    begin
      lSum := lSum + lPtr^[i];
    end;
  finally
    FreeMemory(lPtr);
  end;
end;


Смысл в том, что используется указатель на массив с как бы одним элементом, но ничего не мешает обратиться к элементам с другими индексами по указателю на такой массив.

Автор: Geniebal 16.11.2011, 14:38
сделал как ты написал, получилось равноценно тому что было в начале у меня - ошибка с обращением хз куда

Автор: MetalFan 16.11.2011, 20:47
Ну ищи тогда ошибку в своем коде.
Твой подход по работе с указателем на дин.массив в корне неверный.
Предложенный мной подход вполне жизнеспособен.
Видимо где-то вылет за границы выделенной памяти или нечто подобное.

Автор: Geniebal 17.11.2011, 10:11
Цитата

Твой подход по работе с указателем на дин.массив в корне неверный

Почему? Делаем указатель - выделяем память на определенный размер - образаемся к памяти через указатель как к массиву... Что не правильно?

Автор: CodeMonkey 17.11.2011, 11:33
http://www.gunsmoker.ru/2009/01/blog-post.html - аж 4 варианта кода.

Добавлено через 3 минуты и 55 секунд
Цитата(Geniebal @  16.11.2011,  10:59 Найти цитируемый пост)
если я тупо пишу TArray = array [0..0] of byte, то выдается ошибка типо - попытка обратится к элементу массива вне его диапазона


Можно как-то так:

Код

type
  TArray = array [0..MaxInt div SizeOf(TElem) - 1] of TElem;


Мог ошибиться на единичку в правой границе, но смысл понятен.

Добавлено через 6 минут и 13 секунд
Цитата(Geniebal @  17.11.2011,  11:11 Найти цитируемый пост)
Почему? Делаем указатель - выделяем память на определенный размер - образаемся к памяти через указатель как к массиву... Что не правильно? 


Потому что ты не выделил память под массив. Ты выделили память под данные массива.

Наводящий вопрос: где хранится число, сколько элементов в массиве?

Учим мат-часть: http://www.transl-gunsmoker.ru/2009/09/blog-post.html

Автор: Geniebal 18.11.2011, 11:12
Цитата

Потому что ты не выделил память под массив. Ты выделили память под данные массива.

Наводящий вопрос: где хранится число, сколько элементов в массиве?


При выделении мы же указываем требуемый размер? или это не то?
и тогда просто гениальный вопрос: почему АНАЛОГИЧНАЯ функция Resident_atribute РАБОТАЕТ?

Автор: CodeMonkey 18.11.2011, 11:23
Цитата(Geniebal @  18.11.2011,  12:12 Найти цитируемый пост)
При выделении мы же указываем требуемый размер?


Читай мат-часть по указанным ссылкам. Динамический массив - это не блок памяти. Динамический массив имеет служебный заголовок, который ты игнорируешь.

Код
type
  TArray = array of Integer;
  PArray = ^TArray;

var
  Ptr: PArray;
begin
  Ptr := AllocMem(50 * SizeOf(Integer));
  Caption := IntToStr(Length(Ptr^)); // внимание, вопрос: откуда в этой строчке возникнет число 50? Где оно хранится?
end;


Цитата(Geniebal @  18.11.2011,  12:12 Найти цитируемый пост)
и тогда просто гениальный вопрос: почему АНАЛОГИЧНАЯ функция Resident_atribute РАБОТАЕТ? 


Так кубики выпали.

Автор: Geniebal 23.11.2011, 16:49
Спасибо! Разобрался.

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