Указатели
Автор :
Петр Высочанский
Вернуться на главную Обычно
указатели хранят адрес в памяти того или иного объекта (переменной, структуры,
процедуры и т. д.), т. е. указывают на этот объект. Не скажу что работать с
указателями приходится очень часто, но иногда возникает такая необходимость. Для
хранения адреса памяти существует специальный тип переменной. В начале такой
переменной находится символ
* (звёздочка). То есть это
*pointer
переменная-указатель на область памяти.
PureBasic позволяет получать адреса, переменных,
массивов, структур, связанных списков, процедур и меток.
Адрес метки
можно получить подставив перед её именем символ
?,
адреса остальных объектов можно получить поставив перед их
именем символ
@.
Следующий пример показывает как можно получить адрес переменной и работать с
ней как с
памятью.
var=100 ; Запись числа 100 в переменную
*pointer=@var ;
Поучение адреса переменной
Debug PeekC(*pointer) ; Чтение данных из переменной зная её адрес в
памяти
В первой строке происходит запись числа в
переменную. Узнаём адрес в памяти где хранятся данные этой переменной, поставив
перед её именем "собаку" - символ
@. После чего, с помощью
функции
PeekC происходит чтение данных
из памяти, т. е. из переменной
var.
Помните, в статье
Работа с памятью был
приведён пример программы, которая считываем текст из файла и отображает его в
текстовом редакторе. Там данные сначала копировались из файла в память, а затем
из памяти в строковую переменную. Этот пример можно упростить, исключив работу с
памятью, точнее можно использовать строковую переменную как память. Тогда данные
будут копироваться из файла сразу в переменную.
Пример будет выглядеть
так:
File.s=OpenFileRequester("","","Текстовые файлы (txt)|*.txt",0)
If
File<>""
If ReadFile(0, File) ; Открытие файла
Size=Lof(0) ; Определение размера файла в
байтах
Text.s=Space(Size) ; Заполнение строковой переменной
пробелами
ReadData(0, @Text, Size) ; Копирование данных из файла в
переменную
CloseFile(0) ; Закрытие файла
Else
MessageRequester("", "Не удалось открыть
файл")
End ; Завершение работы программы
EndIf
EndIf
; Открываем окно
OpenWindow(1,0,0,400,400,"Работа с памятью", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(1))
EditorGadget(1,2,2,396,396) ; Создаём текстовый редактор
SetGadgetText(1,Text) ; Помещаем текст из строковой переменной в
редактор
Repeat ; Главный цикл
программы
Event=WaitWindowEvent() ; Получаем идентификатор события в
программе
Until Event=#PB_Event_CloseWindow ; Прерываем цикл если нужно закрыть
окно
Перед чтением теста из файла, в строковую
переменную
Text, с помощью функции
Space записывается число пробелов, равное
размеру файла. Это нужно чтобы зарезервировать в переменной требуемое число
байт. Далее, при помощи функции
ReadData производится копирование данных из
файла в переменную. Функция как и положено получает указатель на память, только
это память, занимаемая переменной.
С помощью указателей можно
возвращать из процедуры более одного результата и при этом не использовать
глобальные переменные. Следующий пример демонстрирует это.
Procedure Test(*var1, *var2)
PokeL(*var1, 12345678) ; Запись числа в память
PokeS(*var2,
"Строка текста") ; Запись текста в
память
EndProcedure
var.l=0
Text.s=Space(100) ; Резервируем данные в строковой переменной,
путём записи 100 пробелов
Test(@var, @Text) ; Вызываем процедуру и передаём ей указатели на
переменные var и Text
;
Отображаем в отладочном окне данные из переменных.
Debug var
Debug
Text
При инициализации переменных, в
var записывается число 0, а в строковую
переменную
Text, записывается 100
пробелов, т. е. резервируется память. Далее вызывается процедура
Test, которой передаются указатели на эти
переменные. В процедуре производится запись данных в эти переменные, причём с
ними производится работа как с памятью. И в конце программы, с помощью оператора
Debug, в отладочном
окне отображается данные из этих переменных.
Но гораздо удобнее работать
со
структурами,
т. к. не нужно использовать функции доступа к памяти.
Structure Proba
x.l
y.l
Text.s
EndStructure
test.Proba ; Объявление структуры
Procedure Test(*var.Proba)
*var\x=1
*var\y=2
*var\Text="Текст"
EndProcedure
Test(@test) ; Вызываем процедуру и передаём ей указатель на
структуру
; Отображаем в
отладочном окне данные из структуры
Debug test\x
Debug test\y
Debug
test\Text
В
следующем примере показано, как можно вызывать процедуру зная её адрес в
памяти.
Procedure Message(Title.s, Message.s)
MessageRequester(Title, Message)
EndProcedure
; Узнаём адрес процедуры и помещаем его в
переменную-указатель
*ponter=@Message()
; Вызываем процедуру зная её адрес в
памяти
CallFunctionFast(*ponter, "Заголовок", "Текст")
Возможность
получать адрес метки, позволяет сохранять различные данные в теле исполняемого
файла используя так называемую ДатаСекцию. Это позволяет хранить, скажем один
или несколько файлов, требуемых для работы программы. Чаще всего это значки,
различные рисунки, музыка и т. д. Можно даже хранить динамическую
библиотеку подпрограмм (исполняемый файл с расширением DLL), которую можно
запускать прямо из памяти.
Следующий пример показывает как можно
поместить значок в исполняемый файл и использовать его в программе.
;
Открываем окно
OpenWindow(1,0,0,80,80,"",#PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(1)) ; Создаём новый список гаджетов
CatchImage(1,?Metka1, ?Metka2-?Metka1) ; Загружаем рисунок из памяти
ImageGadget(2,40,20,32,32, ImageID(1) ) ; Отображаем его
Repeat ; Начало главного цикла
Repeat-Until
Event=WaitWindowEvent() ; Получаем текущий идентификатор
события
; Прерываем
цикл при попытке закрыть окно (щелчёк по крестику в заголовке
окна)
Until Event=#PB_Event_CloseWindow
End ;
Завершаем работу программы
DataSection
Metka1:
IncludeBinary "Значок.ico"
Metka2:
EndDataSection
На
этапе компиляции, с помощью оператора
IncludeBinary в
исполняемый файл записывается файл с именем
Значок.ico, находящийся в одной папке с
исходным текстом. Метки перед и после этого оператора позволяют узнать место в
памяти, где хранится файл, в нашем случае значок, который в функции
CatchImage загружается, а затем отображается
в окне. Первый аргумент этой функции - идентификатор создаваемого рисунка,
второй аргумент - адрес памяти начала рисунка, который получаем с помощью
символа
?
перед именем метки. Третий аргумент - размер памяти в байтах, занимаемый
рисунком. Чтобы его получить, просто отнимаем адрес второй метки от адреса
первой метки.
Скомпилированную программу и её исходный текст можно
скачать здесь
Материалы взяты с сайта : http://pure-basic.narod.ru/docs/point.html
Вернуться на
главную