указатели (pointer)

Предыдущая тема Следующая тема Перейти вниз

указатели (pointer)

Сообщение  Eric-S в Вс Окт 05, 2008 7:29 am

Указатели завоевали сердца программистов уже давно. Но всё ещё ходят те, кто о них и не слышал. Глава рассказывает об указателях вообще и для языка FreeBasic в частности.



введение

Указатель это адрес ячейки памяти, где находяться определённые данные.

В языке ассемблер используються именно указатели, а переменные это их форма представления.
В чистом бэйсике указателей, в явном виде, нет.
Freebasic позаимствовал указатели и способы работы с ними из языка C.

Указатели позволяют работать с данными, в памяти, напрямую. В некоторых случаях, это даёт большое увеличение скорости.

FreeBasic позволяет программисту обращаться с указателями, не сильно задумываясь, над адресным пространством и прочими низкоуровневыми тонкостями. Но я бы посоветовал, всё же изучить этот вопрос. Он не так сложен, как это может показаться.

По своей сути, указатель это адрес, он может быть представлен числом типа uinteger.
А переменная хранящая указатель это переменная типа uinteger.
Но не нужно считать сиё тождественным. В других версиях или на каких-нибудь новых платформах ситуация может быть иной.
Покаже указатель это целое число записанное 4'мя байтами или 32'мя битами.


объявление

Указатели объявляються, также как переменные, но после типа данных необходимо указать специальный модификатор ptr или pointer.

Код:

dim i as integer ' обычная переменная типа integer
dim p as integer ptr ' указатель на данные типа integer

Модификатор pointer тоже самое что ptr это синонимы.
Код:

dim p as integer pointer ' указатель на данные типа integer

Если вы не знаете тип данных, то можно воспользоваться ключевым словом any
Код:

dim p as any ptr ' указатель на данные типа integer

Этот же вариант позволит вам обращаться к разным типам данных.

Но будте аккуратны, поскольку FreeBasic в некоторых случаях, не сможет корректно обработать данные, поскольку не знает какого они типа.

Указывайте соответствующие типы данных, для указателейй.

примечание: если вы создаёте пользовательский тип данных или класс, то вы можете в его теле использовать указатели на него.

Код:

type MyType
value as integer
prev as MyType ptr
next as MyType ptr
end type

Это может помочь вам, например при создании списка.





получение адреса

Чтобы получить адрес данных можно воспользоваться функцией VarPtr, она возвращает адрес данных переменной переданной ей.

Код:

Print VarPtr( i ) ' узнать адрес, где находиться значение переменной i

Но можно это сделать проще, с помощью префикса имени переменной, "@".
Внимание! В языке C, используеться префикс "&".

Код:

print @i ' узнать адрес, где находиться значение переменной i

Этот вариант лучше и быстрее. Функция VarPtr() была сохранена только для совместимости со старыми версиями basic.

Код:

dim i as integer
dim p as integer ptr
i = 7 ' присваиваем значение
p = @i ' задаём указатель
print i ' напечатаем значение i
print p ' напечатаем адрес значения i
sleep

примечание: - нельзя изменить внутренний указатель переменной на данные. Следующий код будет неверен.
Код:

@i = p



получение данных

Получению адреса есть и обратное действие, получение данных по адресу. Для этого используеться префикс, перед именем переменной, "*".
В языке C точно так же.

Код:

print *p ' напечатать значение по адресу в указателе

Обратите внимание, что значение не копируеться, оно одно и тоже!

Код:

dim i as integer
dim p as integer ptr
i = 7 ' присваиваем значение
p = @i ' задаём указатель
i = 33 ' изменим значение
print i ' напечатаем значение i
print p ' напечатаем адрес значения i
print *p ' напечатать значение по адресу в указателе
sleep

В результате мы можем получить что-то вроде:

33
1245064
33

где 33 это наше значение. В первой строке оно было взято из переменной.
Код:

print i

А в последней оно было взято по адресу из указателя.
[/code]
print *p
[/code]

Число же 1245064 это собственно и есть адрес нашего значения.
Код:

print p
или
Код:

print @i

примечание: для одной программы адрес значения может меняться. Это не постоянное значение. Оно зависит от очень многих факторов.


Возможно вы обратили внимание на то, что в начале число было 7, но потом мы изменили его на 33.
Указатель же был получен и вернул нам именно адрес, а что по этому адресу записано уже неважно. Адрес не меняеться если изменить значение.

Код:

dim i as integer = 22
print @i
i = 33
print @i
sleep

У меня эта программка вывела

1245064
1245064
Адреса идентичны, хоть значения разные.

примечание: со строками и массивами это особый случай. Там несколько другой механизм присвоения значений.



изменение по указателю

Мы можем не только получать данные по указателю, но и менять их. Давайте посмотрим это на примере.
Код:

dim i as integer
dim p as integer ptr
i = 7 ' присваиваем значение
p = @i ' задаём указатель
*p = 33 ' изменим значение через указатель
print i ' напечатаем значение i
sleep

Выведёт нам

33
Хотя мы использовали именно указатель. Префикс "*" позволяет нам не только получать, но и изменять данные.
Код:

*p = 33



изменение адреса

По идеи это должно работать, но не работает.

Код:

dim i1 as integer = 111
dim i2 as integer = 222
dim tmp as integer ptr

print i1, i2 ' выведет 111 222
tmp = @i1
@i1 = @i2
@i2 = tmp
print i1, i2 ' выведет 222 111
sleep


алгебра указателей

Указатели можно складывать, вычитать и делать некоторые другие математические действия.
Но всё зависит от типа данных, точнее размера этих данных.

Код:

' создаём массив
dim a(0 to 9) as integer

' заполним массив
dim i as integer
for i = 0 to 9
a(i) = i
next

' указатель на начальный элемент
dim p as integer ptr

' получим несколько значений
p = @a(0)
print "a(0) = ", *p, p
print "a(1) = ", *(p + 1), p + 1
print "a(9) = ", *(p + 9), p + 9
sleep

выведет нам

a(0) = 0 1245028
a(1) = 1 1245032
a(9) = 9 1245064

Берём указатель для начального элемента массива a(0).
Прибавляем 1, в смысле перейти к следующему элементу массива a(1).
Но реально адрес измениться на 4, что мы можем видеть при выводе.
был 1245028, а стал 1245032.
В нашем случае учитываеться размер данных типа integer, он равен 4.
Код:

print len( integer )
sleep

Если бы массив был другого типа, то результат был бы тот же, за исключением разницы адресов. Попробуйте изменить integer на ubyte.

указатели на пользовательские типы и объекты

О типах и объектах читайте в соответствующих главах.
пользовательские типы данных
классы, методы, свойства и объекты.
Далее, я буду писать о полях пользовательских типов, но это справедливо для свойств и методов класса.

При работе с указателями есть различие. Например если вы создали тип данных
Код:

type MyType
id as integer
name as string
value as string
end type

То к полям вы обращаетесь через точку ".".
Код:

dim myVar as MyType

' заполняем
myVar.id = 325
myVar.name = "FreeBasic"
myVar.value = "FreeBasic is programming language."

' выводим
print "myVar: " & myVar.id & myVar.name & " " & myVar.value
sleep

Когда же вы используете указатель, то обращаться к значению полей нужно с помощью знака "->".

Вот тот же самый пример, но с указателем.

Код:

dim myVar as MyType
dim p as MyType ptr = @myVar

' заполняем
p->id = 325
p->name = "FreeBasic"
p->value = "FreeBasic is programming language."

' выводим
print "myVar: " & p->id & p->name & " " & p->value
sleep


заключение

Мы познакомились с указателями. Как их создавать, управлять ими. А вот то как вы будете их применять в своей программе, уже решать вам.

В качестве напутствия, посоветую придерживаться золотой середины. Не отказывайтесь от них, но и не злоупотребляйте.

Разумно распоряжайтесь этим острым инструментом, в небрежных руках он может быть опасен.

смотрите также:
строки из нутри и указатели


Последний раз редактировалось: Eric-S (Пн Окт 06, 2008 5:38 am), всего редактировалось 2 раз(а)

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Вс Окт 05, 2008 7:33 am

Я сейчас перерабатывал главу, которая была у меня написана ещё летом. И по ходу всплыли ещё вопросы.

Например мне казалось, что такой код, должен работать, но выскочила ошибка.
Код:

dim i1 as integer = 111
dim i2 as integer = 222
dim tmp as integer ptr
print i1, i2 ' выведет 111 222
tmp = @i1
@i1 = @i2
@i2 = tmp
print i1, i2 ' выведет 222 111
sleep

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  justar в Вс Окт 05, 2008 8:02 am

Eric-S пишет:
Например мне казалось, что такой код, должен работать, но выскочила ошибка.
Думаю, что ошибка здесь:
Код:

@i1 = @i2
Ты пытаешься адрес переменой i2 присвоить адресу переменной i1, т.е изменить адрес переменной i1.

justar

Сообщения : 135
Дата регистрации : 2008-05-12
Возраст : 43
Откуда : Кишинёв, Республика Молдоа

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Вс Окт 05, 2008 8:06 am

Именно. В том-то и была соль. Но fb мне такое не позволил.
А в C номер, кажеться, срабатывает.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  justar в Вс Окт 05, 2008 8:34 am

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

justar

Сообщения : 135
Дата регистрации : 2008-05-12
Возраст : 43
Откуда : Кишинёв, Республика Молдоа

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Вс Окт 05, 2008 8:44 am

Я мог и перепутать. Не утверждал, что это так и есть.
Возможно не в си, а в другом каком-то языке.

Идея была в том, чтобы изменить внутренние указатели переменной i1 и i2, чтобы они объменялись значениями.

Возможно это фокус для строк.

Но на такую мысль меня именно белая книга натолкнула. Правда Кернегана & Ричи я уже читал довольно давно.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Вс Окт 05, 2008 8:50 am

Кажись я плохо подумал. Ведь действительно, указатель на переменную должен быть жостко вбит. Точнее не указатель а смещение. И его-то изменить должно быть запарно.
Прошу прощенья - ступил.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

указатели (pointer)

Сообщение  electrik в Вс Окт 05, 2008 4:40 pm

привет. ну раз уж заговорили про указатели, вот вам еще один пример, как можно работать с указателем на элементы определенного типа данных.
оператор "->"
код:
type d3 'создадим тип из трех integer элементов
x as integer
y as integer
z as integer
end type

dim s as d3
dim sp as d3 ptr = @s 'создаем указатель типа d3 и получим адрес
sp->x=2 'уже через указатель обращаемся к элементам нашекго типа
sp->y=4 ' оператором "->"
sp->z=1 'и пишем внаши элементы значения

'выведем таким же образом все элементы на экран
print sp->x,sp->y,sp->z
sleep

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Пн Окт 06, 2008 1:51 am

Эхе-хей, уважаемый Электрик. Спасибо за дополнение, это тут не совсем в тему, ну да можно и вставить.

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

Вот если бы вы ещё указали, что и почему, в смысле на кой это нужно, в отрыве от объектов?

Ладно, добавил и это. Информация лишней не бывает.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  justar в Пн Окт 06, 2008 10:44 am

Ну это он дабавил про указатели на структуры. Дополнение важное, по-моему.
А что касается "указателей в отрыве от классов", т.е. их другие применения (?), то можно сказать следующее:
1. более быстрый, чем через POKE и PEEK прямой доступ к ячейкам памяти (UBYTE PTR)
2. более гибкая и быстрая работа с массивами и строками
3. списки и деревья (см. мою статью о них)
4. передача параметров в функции
Кстати, что ещё не отражено у тебя - так это указатели на функции (часто требуютсяЮ например, при вызове функций Win32API)

justar

Сообщения : 135
Дата регистрации : 2008-05-12
Возраст : 43
Откуда : Кишинёв, Республика Молдоа

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Eric-S в Пн Окт 06, 2008 10:50 am

justar, ок, понял.
А не мог бы ты, или ещё кто-нибудь, написать подраздел про указатели на функции. Не чувствую себя уверенно в этом вопросе.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: указатели (pointer)

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


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