Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16

Как скопировать структуру или сменить указатель новой переменной на ее адрес

13.09.2014, 17:14. Показов 2497. Ответов 33
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!

У меня есть структура вида:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
type Struct_inside
    a as long
    b as long
end type
 
type Struct_main
    count as long
    arr() as Struct_inside
end type
 
public BIDS() as Struct_main
Я заполняю ее некоторыми данными, например:

Visual Basic
1
2
3
4
5
6
sub form_load()
    Redim BIDS(0 to 1) as Struct_main
    Redim BIDS(0).arr(0) as Struct_inside
    BIDS(0).arr(0).a = 11
    BIDS(0).arr(0).b = 22
end sub
И теперь мне тупо лень обращаться к переменным вот так:

Visual Basic
1
2
3
4
5
6
msgbox BIDS(0).arr(0).a
'я конечно могу сделать вот так:
with BIDS(0).arr(0)
   msgbox .a
end with
'но мне хочется поизвращаться :)
Вместо этого мне хочется создать:
Visual Basic
1
2
3
4
5
Dim SI as Struct_inside
' и скопировать в нее структуру BIDS(0).arr(0)
' чтобы потом обращаться к переменным a и b вот так:
msgbox SI.a
msgbox SI.b
Я конечно могу сделать вот так:
Visual Basic
1
2
SI.a = BIDS(0).arr(0).a
SI.b = BIDS(0).arr(0).b
Но уверен есть более простой способ:
1) скопировать структуру через какую-нибудь CopyMemory.
2) сменить указатель переменной SI на адрес структуры BIDS(0).arr(0)

Примерно так я это представляю.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
13.09.2014, 17:14
Ответы с готовыми решениями:

Как из компонента ActiveX вернуть указатель на структуру или класс
День добрый! Есть такая проблема: не получается вернуть из компонента ActiveX вернуть указатель на структуру. Информации по этому поводу в...

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

Изменяется ли адрес или значение переменной при объявлении ее как const?
При объявлении const у нас значение переменной или адрес переменной не изменяется?

33
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
13.09.2014, 17:55
Лучший ответ Сообщение было отмечено Dragokas как решение

Решение

Цитата Сообщение от Dragokas Посмотреть сообщение
Я конечно могу сделать вот так:
Visual Basic
1
2
SI.a = BIDS(0).arr(0).a
SI.b = BIDS(0).arr(0).b
Зачем по полям копировать когда можно просто:
Visual Basic
1
SI = BIDS(0).arr(0)
Скопировать можно и через CopyMemory, но в этом нет смысла, причина описана выше.
Также можно сменить указатель на структуру, об этом можешь почитать тут.
2
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
13.09.2014, 18:01  [ТС]
Ай.
А я пытался сделать тоже самое через set
Спасибо.
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
13.09.2014, 18:02
Цитата Сообщение от Dragokas Посмотреть сообщение
А я пытался сделать тоже самое через set
Set присваивает объектной переменной ссылку на объект и увеличивает счетчик использования объекта.
2
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
18.09.2014, 02:24  [ТС]
А вот можно ли скопировать байтовый массив поверх структуры ?
Т.е. таким образом, чтобы не нужно было вручную заполнять по полям.

По сути, я считываю файл, создаю структуры согласно спецификации типа файла
и накладываю куски считанных данных на эти структуры.
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
18.09.2014, 02:28
Цитата Сообщение от Dragokas Посмотреть сообщение
А вот можно ли скопировать байтовый массив поверх структуры ?
Т.е. таким образом, чтобы не нужно было вручную заполнять по полям.
Можно. Используй RtlMoveMemory (в народе CopyMemory) где первым параметром передавай структуру, вторым - первый элемент массива, третьим - Len(структура). Только там есть ньюансы при копировании некоторых типов данных.
Цитата Сообщение от Dragokas Посмотреть сообщение
По сути, я считываю файл, создаю структуры согласно спецификации типа файла
и накладываю куски считанных данных на эти структуры.
Почему бы сразу не читать в структуры?
1
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
18.09.2014, 03:19  [ТС]
Ух ты. Я и не предполагал, что барсик на столько умный ))

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Private Type STRUCT_Header
    HeaderSize As Long
    GUID As String * 16
    Flags As Long
End Type
    
Private Sub Form_Load()
    Dim ff      As Integer
    Dim sFile   As String
    Dim Header  As STRUCT_Header
    ff = FreeFile()
    
    sFile = "c:\users\alex\desktop\avz.lnk"
    
    Open sFile For Binary Access Read As #ff
        Get #ff, 1, Header
    Close #ff
End Sub
Работает. Спасибо.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
15.11.2014, 23:32  [ТС]
The trick, можешь, пожалуйста, написать простой пример,
как создать массив указателей на уже созданные объекты, так чтобы затем
через For Each можно было переназначить эти ссылки на адрес нового объект.

Вот здесь в коде у меня в массиве дублируется объект, а нужно работать через ссылки.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Option Explicit
 
Private Sub Form_Load()
 
    Dim col_spec As Object
    Dim col_anim As Object
    Dim cols
    Dim col
    Dim NC As Object
    Dim i As Long
    
    Set col_anim = New Collection
    Set col_spec = New Collection
    col_anim.Add "1"
    col_spec.Add "1"
    
    Debug.Print "col_anim addr=" & ObjPtr(col_anim)
    Debug.Print "col_spec addr=" & ObjPtr(col_spec)
    
    ' Создаем массив объектов (а на самом деле, я так понял объекты просто были скопированы)
    cols = Array(col_anim, col_spec)
    
    ' Создаем временный объект
    Set NC = New Collection
    NC.Add "2"
    Debug.Print "NC addr="; ObjPtr(NC)
    
    For i = 0 To UBound(cols)
        Debug.Print "old col addr=" & ObjPtr(cols(i))
        Set cols(i) = NC    ' <--- как здесь для объектов, которые содержатся в массиве cols, переназначить ссылку на коллекцию NC
        
        Debug.Print "new col addr=" & ObjPtr(cols(i))
    Next
    
    Set NC = Nothing
    
    Debug.Print "-----------"
    
    For i = 0 To UBound(cols)
        Debug.Print "col addr="; ObjPtr(cols(i))
        Debug.Print cols(i).Item(1)
    Next
    
    Debug.Print "col_anim addr=" & ObjPtr(col_anim)
    Debug.Print "col_spec addr=" & ObjPtr(col_spec)
    Debug.Print col_anim.Item(1)
 
End Sub
col_anim addr=216834632
col_spec addr=216833736
NC addr= 216833512
old col addr=216834632
new col addr=216833512
old col addr=216833736
new col addr=216833512
-----------
col addr= 216833512
2
col addr= 216833512
2
col_anim addr=216834632
col_spec addr=216833736
1
Последняя цифра должна получится 2, а не 1.
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
15.11.2014, 23:56
Цитата Сообщение от Dragokas Посмотреть сообщение
' Создаем массив объектов (а на самом деле, я так понял объекты просто были скопированы)
Нет. Создался массив с ссылками на оригинальные объекты и счетчик ссылок оригинальных объектов увеличился. Можешь потом выполнить col_anim.Add "444" и посмотреть, у тебя и в массиве и в переменной col_anim отобразится.
Цитата Сообщение от Dragokas Посмотреть сообщение
<--- как здесь для объектов, которые содержатся в массиве cols, переназначить ссылку на коллекцию NC
Опять же в массиве cols содержаться не объекты, а ссылки на те же объекты на которые ссылаются col_anim и col_spec, поэтому эта запись лишена смысла. В массиве нет объектов, а есть ссылки. Делая все эти манипуляции у тебя ссылка NC и оба элемента массива ссылаются на один и тот же объект.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
16.11.2014, 00:07  [ТС]
Допустим, если я в массиве буду хранить адреса переменных col_anim, col_spec,
как сменить их ссылку на новый объект (NC) ?
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.11.2014, 00:41
Цитата Сообщение от Dragokas Посмотреть сообщение
Допустим, если я в массиве буду хранить адреса переменных col_anim, col_spec,
как сменить их ссылку на новый объект (NC) ?
Тебе нужна ссылка на ссылку? Так можешь через промежуточный объект это сделать. В массиве храни ссылку на свой объект, который имеет у себя объектное свойство, которое будет указывать на col_anim.
Если ты хочешь ссылаться по двойной ссылке, то нужен еще промежуточная переменная для хранения ссылки на целевой объект.
Если, как ты говоришь есть адреса, то можно через __vbaObjSetAddref присвоить объектной переменной ссылку на объект по адресу, но это излишне.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
16.11.2014, 01:02  [ТС]
Поясню на практической задаче.
Делаю сортировку словаря методом, описанным мною здесь: Сортировка словаря методом реконструкции

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

*1 - В той теме я присваиваю исходной переменной ссылку на новый объект ("промежуточный словарь" с отсортированными данными).

Но реально, мне нужно таким же образом отсортировать много словарей.
А они создавались не как массив объектов, а как отдельные объектные переменные (*2).

Поэтому мне надо их как-то собрать в массив.
Но с эл-тами массива такой фокус (см. *1) не получается, т.к. ссылка на объект меняется у переменной массива,
а не каждой отдельной исходной объектной переменной (*2).
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.11.2014, 01:16
Dragokas, я понял тебя.
Примерно так
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Private Sub Form_Load()
    Dim p As New Collection
    Dim q As New Collection
    
    p.Add "4"
    q.Add "8"
    
    Foo p, q
    
End Sub
 
Private Sub Foo(ParamArray z())
    Set z(0) = New Collection   ' p
    Set z(1) = New Collection   ' q
    z(0).Add "t"
    z(1).Add "u"
End Sub
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
16.11.2014, 02:09  [ТС]
Конечно, есть и альтернативный способ - не сортировать словарь вообще:
в функции сортировки создавать для каждого словаря массив, который будет хранить порядок чтения эл-тов словаря.

И когда его нужно будет его прочесть, то пользоваться не
Visual Basic
1
for each key in .keys
а этим массивом расположений эл-тов.
Но тогда со словарями всегда придется как-то тягать для каждого свой массив позиций.

Добавлено через 7 минут
The trick, хм..., да, вполне можно и перечислить все их имена как параметры функции сортировки,
не собирая в массив.
Спасибо.

Добавлено через 44 минуты
Единственная огласка для тех, кто читает тему:
чтобы у всех переданных переменных (у нас - это p, q) сменить ссылку на другой объект, находясь в функции Foo,
нужно использовать цикл не "For...each", а конструкции вида:
Visual Basic
1
2
3
For i = 0 to UBound(z)
set z(i) = new collection
...
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
16.11.2014, 17:50
Не знаю в тему это или нет, но есть такой способ работы с указателями на структуру:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
' Функция-посредник
Private Sub func_SetDefaults(frm As FormMain, _
       ByVal begin_of_pointers As Long, _
       ByRef RecordFill As TYPE_WPC_FILL)
 
    Dim StepPointer As Long
 
    StepPointer = Manager.DataPointer + _
       Manager.ProgramIndex * PROGRAM_SIZE_IN_BYTES + _
       HEADER_SIZE_IN_BYTES + _
       Manager.StepIndex * STEP_SIZE_IN_BYTES
 
    PutMem4 VarPtr(begin_of_pointers) + 4, ByVal StepPointer
 
'...
 
    ' Аналоговые типы
    RecordFill.Level = Level.DefaultValue
    RecordFill.RotationTime = RotationTime.DefaultValue
    RecordFill.PauseTime = PauseTime.DefaultValue
    RecordFill.DrumSpeed = DrumSpeed.DefaultValue
 
End Sub
 
Public Sub SetDefaults(frm As FormMain)
    Dim RecordFill As TYPE_WPC_FILL
 
    func_SetDefaults frm, 0&, RecordFill
End Sub
Давно уже описан в блоге у Хакера с альтернативного форума.

Я не знал, что можно сложные вещи и массивами делать, как тут The trick показывал, поэтому в своей программе, там где нужны были указатели на пользовательские структуры, я использовал вспомогательные функции и трюк со стеком.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
16.11.2014, 17:54  [ТС]
Спасибо.
Но, мне например, без комментариев не понять, что там происходит
и для чего это вообще используется -(
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.11.2014, 18:03
Если требуется только чтение, то можно сделать через Variant'ы так -
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Option Explicit
 
Private Declare Function PutMem4 Lib "msvbvm60" (Src As Any, ByVal Dst As Long) As Long
 
Private Sub MakeByRefPointer(Pointer As Variant, ByVal VarType As VbVarType, ByVal Address As Long)
    PutMem4 Pointer, CInt(VarType Or &H4000)
    PutMem4 ByVal VarPtr(Pointer) + 8, Address
End Sub
Private Sub ChangePointer(Pointer As Variant, ByVal Address As Long)
    PutMem4 ByVal VarPtr(Pointer) + 8, Address
End Sub
 
Private Sub Form_Load()
    Dim z As Variant
    Dim s As String
    Dim q As String
    
    s = "The trick"
    q = "Visual basic 6"
    
    MakeByRefPointer z, VarType(s), VarPtr(s)
    ' z óêàçûâàåò íà s
    ChangePointer z, VarPtr(q)
    ' z óêàçûâàåò íà q
    
End Sub
1
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
16.11.2014, 18:03
По началу сложно, да. Если найду описание, то дам ссылку. Дело вот в чём. Предположим, что у нас в памяти есть массив элементов пользовательского типа. Мы знаем адрес, с которого он начинается, нам нужен указатель на элемент массива такой, чтобы мы могли работать с идентификатором как с переменной. Т.е. мы объявляем "типизированный указатель", который у нас есть в памяти (ByRef RecordFill As TYPE_WPC_FILL) и присваиваем RecordFill адрес нужного участка памяти: PutMem4 VarPtr(begin_of_pointers) + 4, ByVal StepPointer

После этой конструкции внутри вспомогательной функции мы можем напрямую работать с этим участком памяти через пользовательскую переменную RecordFill, как показано выше.
1
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
16.11.2014, 18:05
уни, так это же через стек.
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
16.11.2014, 18:31
Да, именно через стек, очень просто и красиво получается. Не нужно ничего лишнего, кроме вспомогательной функции, где одним из параметров должна быть маркированная переменная (&0), она используется для вычисления адреса нужного "типизированного указателя". Можно через запятую указать больше таких "указателей" на разные пользовательские типы.

Добавлено через 22 минуты
Я, кстати, не помню почему Хакер делал это именно таким образом. У него там целая статья была с разъяснениями.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.11.2014, 18:31
Помогаю со студенческими работами здесь

Вычислить адрес верхушки стека, адрес следующей команды, адрес переменной, адрес которой содержится в BX
Помогите решить следующие задачи: 1.Вычислить адрес верхушки стэка. 2.Вычислить адрес следующей выполняемой программы. 3. Вычислить...

Как получить ссылку на указатель или указатель на указатель в массиве?
В процессе реализации сортировки пузырьком натолкнулся на такую проблему: как поменять значения указателей, передаваемых в функцию. Если...

Как сменить IP адрес?
Суть проблемы: никак не могу скинуть IP адрес. Менял и MAC адреса железа, и через командную строку ipconfig /release и ipconfig /renew...

Как сменить IP адрес
день добрый. не подскажите как программно заставить венду сменить IP ?

Передать функции структуру из массива структур или указатель на неё
передать функции структуру из массива структур или указатель на неё в качестве параметра. покажите пример.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru