Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Архив форумов ЦИТФорума
Море(!) вопросов - Море(!) ответов
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Как правильно задавать вопросы

Проблемы с указателями в Delphi

 
Перейти:  
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование
Предыдущая тема :: Следующая тема  
Автор Сообщение
RAPTORGrrr



Зарегистрирован: 11.09.2007
Сообщения: 2

СообщениеДобавлено: Вт Сен 11 2007 12:29    Заголовок сообщения: Проблемы с указателями в Delphi Ответить с цитатой

Здравствуйте!
Есть такая проблема:
По com-порту получаю пакет данных, и определяю его тип по заголовку.
Всего есть пять различных пакетов, и все они могут содержатся в одной посылке данных.
Подумал что быстрее будет, если использую указатели, т.е. найду в памяти нужный кусок данных
и типизую его к своему типу TTargetPackage.
Сделал так:

var PtrData : pointer;

GetMem(PtrData, 75 );
PtrData := @Answer[0]; // здесь Answer динамический массив, который содержит нужный кусок данных
Target := TTargetPackage(PtrData^); // это вроде как типизация
FreeMem(PtrData); // ВОТ ТУТ ругается Invalid pointer operatoin
PtrData:=nil;

// TTargetPackage - это запись;
// Target - принадлежит типу TTargetPackage

Почему?
Где что не так?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
igor406



Зарегистрирован: 27.06.2007
Сообщения: 11

СообщениеДобавлено: Ср Сен 12 2007 12:34    Заголовок сообщения: Ответить с цитатой

to RAPTORGrrr
Цитата:

PtrData := @Answer[0]; // здесь Answer динамический массив, который содержит нужный кусок данных
Target := TTargetPackage(PtrData^); // это вроде как типизация


проблема в том, что не кусок данных, а весь массив ты пытаешся привести к типу TTargetPackage, а во вторых, TTargetPackage - это class или record?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
RAPTORGrrr



Зарегистрирован: 11.09.2007
Сообщения: 2

СообщениеДобавлено: Ср Сен 12 2007 14:46    Заголовок сообщения: Ответить с цитатой

Спасибо за внимание, igor406!
По поводу типов
Answer определен как TPack = packed array of byte.
TTargetData - это запись.
TTargetData = packed record
Breadth : single;
Longitude : single;
RAW : array [1..8] of single;
end;
Не хотел нагружать подробностями кода, но если без этого никак...
Вот что в исходнике.

function TfrmMain.AnalysePackage ( Answer : TPack): word;
var
PtrData : Pointer;
Position : word;
EndPackage : word;
begin
Position:=0; // текущая позиция в пакете

while Position <= High(Answer) do // проходим по всему пакету
begin
case Answer[Position] of // Проверяем заголови
TargetID : // пакет целевых данных
begin
EndPackage:= Position+SizeTarget-1; // Определяем конечную позицию
GetMem(PtrData,SizeTarget); // SizeTarget - 75 байт
PtrData := @Answer[Position];
Target:= TTargetPackage(PtrData^);
Freemem(PtrData);
PtrData:=nil;
Position:=Position+SizeTarget+1; // Установка позиции на след. байт
TargetUpdate:= true; // признак обновления данных
Result:=1;
end;

AirborneSystemStatusID: // пакет статуса системы
begin
// Аналогично
end;
MatterID : // пакет веществ
begin
// Аналогично
end;
TimeDateID : // пакет времени
begin
// Аналогично
end;
EvolutionID : // пакет крен/тангаж
begin
// Аналогично
end;
MotionID : // пакет курс/высота
begin
// Аналогично
end;
else exit;
end; // case
end; // while новый проход по пакету
end;

Пример:
Answer содержит 55 5D 42 25 06 2D 41 D5 78 C9 ... BF CF
Начиная с адреса @Answer[0] (значение 55) память содержит нужные мне 75 байт.
Я в PtrData копирую этот адресс, и выделяю память Getmem'ом под них. Затем типизую.
До этого все идет хорошо и в Target содержатся верные данные. Но когда освобождаю память, то вылетает ошибка - Invalid pointer operation.
Вроде бы простая операция: занял память Getmem, освободил FreeMem, но вот затыка - именно на FreeMem прога валится с ошибкой Invalid pointer operation.
А если сделать так:
PtrData:=nil;
Freemem(PtrData);
то все нормально, кроме того что потерял кусок памяти.
Что делать?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
igor406



Зарегистрирован: 27.06.2007
Сообщения: 11

СообщениеДобавлено: Ср Сен 12 2007 15:35    Заголовок сообщения: Ответить с цитатой

to RAPTORGrrr

GetMem и FreeMem работают с линейными непрерывными кусками памяти.
Потому использовать их надо при работе с простыми типами.
И зачем так заморачиваться, если при выходе из процедуры память автоматически отводимая под простые локальные переменные при их объявлении возвращается в кучу (освобождается).
Единственно, когда её нужно освобождать самостоятельно - это при работе с объектами.

Ну, а если всёже необходимо выделять и освобождать память под объекты типа рекордов (но отнюдь не для классов), то необходимо использовать процедуры New и Dispose, хотя на самом деле всё это пережитки прошлого, и при нормальной организации структуры программы на современном этапе необходимости в этом практически нет.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
критикан



Зарегистрирован: 18.02.2005
Сообщения: 247

СообщениеДобавлено: Чт Сен 13 2007 08:29    Заголовок сообщения: Кто дурнее: Паскаль: нельзя 'A'=65 или Си: нужно 'A'==65? Ответить с цитатой

RAPTORGrrr писал(а):
Здравствуйте!
Сделал так:

var PtrData : pointer;

GetMem(PtrData, 75 );
PtrData := @Answer[0]; // здесь Answer динамический массив, который содержит нужный кусок данных
Target := TTargetPackage(PtrData^); // это вроде как типизация
FreeMem(PtrData); // ВОТ ТУТ ругается Invalid pointer operatoin
PtrData:=nil;

// TTargetPackage - это запись;
// Target - принадлежит типу TTargetPackage

Почему?
Где что не так?

Причина очень простая: после выполнения

GetMem(PtrData, 75)

указатель PtrData содержит адрес выделенной области памяти (это называется "указывает на неё"), а после выполнения (ВНИМАНИЕ!)

PtrData := @Answer[0]

указатель PtrData содержит ДРУГОЙ адрес -- он указывает не на память, выделенную оператором GetMem(PtrData, 75), а на память для переменной Answer. Соответственно, команда

FreeMem(PtrData)

пытается освободить совершенно другую память.

Чтобы проверить эти соображения, нужно посмотреть, что содержится в переменной PtrData сразу после GetMem(PtrData, 75) и после PtrData := @Answer[0]. Это будут разные числа -- адреса РАЗНЫХ участков памяти. Освобождать можно область по адресу, полученному после GetMem(PtrData, 75), а не после PtrData := @Answer[0]

Это диагноз.

Теперь лечение.

Никаких GetMem/FreeMem не нужно, так как указатель PtrData используется для адресации уже выделенных участков памяти: память была выделена при определении переменных Answer и Target. и происходит просто копирование информации из одного (уже имеющегося) участка в (уже имеющийся) другой. Паскалисты, умрите от зависти: в Си это делается просто копированием одного участка памяти в другой, так как типизация выполняется УКАЗАНИЕМ типа, а не ВВОДОМ специальной переменной
-------------------------------------------------------------------
Ну и кто дурнее: Паскаль с недопустимым 'A'=65 или Си с обычным 'A'==65?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2002 phpBB Group
Русская поддержка phpBB

 

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 6608306, ICQ 232284597
Пресс-релизы — pr@citforum.ru
Послать комментарий
Информация для авторов
This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2006 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...