Page 1 of 1
Pointers, modules and structure
Posted: Fri Jan 08, 2016 7:18 pm
by s0ula55a551n
Why does this not work as you would expect. This has been driving me mad all afternoon.
The procedure in the module is returning the newly created structure, or at least the memory location as you cannot return a structure from a procedure for some reason.
I am then creating a pointer structure and assinging that memory value to it, and then attempting to access the variable in that pointed structure but its always zero or garbage. I have included the code below. is it just because I am trying to do something I shouldn't ? It makes sense to me this would work.
This is all just test code to see how all these things hang together. Any advice would be welcome. Can confirm that memory addresses of all the debugs are as you expect except the final variable debug
Code: Select all
DeclareModule obj_Create
Structure cords
x.i
y.i
EndStructure
Structure obstacle
top.i
bottom.i
left.i
right.i
EndStructure
Structure slope
left.i
right.i
EndStructure
Structure tile
size.i
location.cords
sprite.i
walk_sound.i
land_sound.i
obs.obstacle
ladder.i
moving.i
prev.slope
current.slope
nxt.slope
EndStructure
Structure object
loc.cords
List up_sprites.i()
List down_sprites.i()
List left_sprites.i()
List right_sprites.i()
List attack_sprites.i()
List death_sprites.i()
hp.i
score.i
health.i
*death.object
*attack.object
pickup.i
curr_x_dir.i
curr_y_dir.i
jumps.i
falls.i
enemy.i
x_speed.i
y_speed.i
EndStructure
Structure player Extends object
lives.i
max_lives.i
continues.i
EndStructure
Enumeration enemyType
#Ghost
#Goblin
EndEnumeration
Declare createEnemy(type)
EndDeclareModule
Module obj_Create
Procedure createEnemy(type)
newEnemy.object
With newEnemy
\curr_x_dir = 44
EndWith
Debug "memory address of new enemeny in proc = " + @newEnemy
*en1.Object = @newEnemy
Debug "contents of new copied obj in proc " + *en1\curr_x_dir
ProcedureReturn newEnemy
EndProcedure
EndModule
testenemy.obj_Create::Object
testenemy\curr_x_dir = 250
Debug "Frist object create : " + testenemy\curr_x_dir
*enemy1.obj_Create::Object = testenemy
Debug "object copie to another object : " + *enemy1\curr_x_dir
NewList testPointers.obj_Create::object()
AddElement(testPointers())
*test.obj_Create::Object = obj_Create::createEnemy(1)
Debug *test
Debug *test\curr_x_dir
;Debug *testPointers()\curr_x_dir
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 8:23 pm
by infratec
Hi,
I think you made one big mistake:
You never 'create' something new.
You only return an address of a structure which gones after your next call.
If you want to create something dynamically, than you have to use AllocateMemory() or, in your case, AllocateStructure()
for 'creation'. And if it is later not needed anymore, you have to free it.
Bernd
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 8:27 pm
by sys64802
I suggest you to read well the manual about pointers and structures, and to do more experiments with them and some code simpler than this one because a lot of things here makes no sense whatsoever.
Start simpler.
To answer your question, you are creating a structure newEnemy of type object on the stack of the procedure createEnemy().
Then you return the base address of that structure and exit the procedure.
Upon leaving, the space on the stack for that structure and any other local variable is freed.
Then you try to access an element from that structure which does not exists anymore by coping its defunct address to a structured pointer of type object.
So you get garbage.
Other suggestions: use EnableExplicit, use Define or Global to define a var instead of throwing its name.type in the middle of the source (IMO the compiler should complain there because it has no meaning), and use @ when passing the address of a structure (it could help you in the future).
Yes, PB cannot return a structure, you can implement e mechanism to copy back a structure in a passed buffer preallocated by the caller if you like, see CopyStructure() and its family, it's equivalent of what many languages returning structures do, only there is invisible.
And yes, to dynamically allocate an "object" you have to allocate it by yourself like infratec said.
edit: pasted something in the wrong place...
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 8:37 pm
by infratec
Maybe something like this:
Code: Select all
EnableExplicit
DeclareModule obj_Create
Structure cords
x.i
y.i
EndStructure
Structure obstacle
top.i
bottom.i
left.i
right.i
EndStructure
Structure slope
left.i
right.i
EndStructure
Structure tile
size.i
location.cords
sprite.i
walk_sound.i
land_sound.i
obs.obstacle
ladder.i
moving.i
prev.slope
current.slope
nxt.slope
EndStructure
Structure object
loc.cords
List up_sprites.i()
List down_sprites.i()
List left_sprites.i()
List right_sprites.i()
List attack_sprites.i()
List death_sprites.i()
hp.i
score.i
health.i
*death.object
*attack.object
pickup.i
curr_x_dir.i
curr_y_dir.i
jumps.i
falls.i
enemy.i
x_speed.i
y_speed.i
EndStructure
Structure player Extends object
lives.i
max_lives.i
continues.i
EndStructure
Enumeration enemyType
#Ghost
#Goblin
EndEnumeration
Declare.i createEnemy(type)
EndDeclareModule
Module obj_Create
Procedure.i createEnemy(type)
Protected *newEnemy.object
*newEnemy = AllocateStructure(object)
*newEnemy\curr_x_dir = 44
*newEnemy\enemy = type
Debug "contents of new copied obj in proc " + *newEnemy\curr_x_dir
ProcedureReturn *newEnemy
EndProcedure
EndModule
Define testenemy.obj_Create::object
Define *enemy1.obj_Create::object
Define *test.obj_Create::object
testenemy\curr_x_dir = 250
Debug "Frist not created object: " + testenemy\curr_x_dir
*enemy1 = testenemy
Debug "object not copied, only address copied: " + *enemy1\curr_x_dir
NewList testPointers.obj_Create::object()
AddElement(testPointers())
*test = obj_Create::createEnemy(obj_Create::#Goblin)
Debug *test\curr_x_dir
Debug *test\enemy
FreeStructure(*test)
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:07 pm
by sys64802
I probably prefer the dynamic allocation method, but this can have its place too
Code: Select all
Structure out
sum.i
sqr.f
Array s$(10)
EndStructure
Procedure ReturnStructure(*ret, a, b, c, s$)
Protected ret.out
ret\sum = a + b + c
ret\sqr = Sqr(a+b+c)
For i = 0 To 10
ret\s$(i) = s$
Next
CopyStructure(@ret, *ret, out)
EndProcedure
Procedure test()
Protected RetVal.out
ReturnStructure(@RetVal, 10, 20, 30, "Hallo")
; equivalent to the unsupported:
; RetVal = ReturnStructure(10, 20, 30, "Hallo")
Debug RetVal\sum
Debug RetVal\sqr
Debug RetVal\s$(0)
Debug RetVal\s$(10)
; something like this has the advantage the "returned" value is deallocated automatically at procedure exit
; without the need to track its address and use Free*.*() on it
; the nice feature you get with real objects ...
EndProcedure
test()
This is not limited to work with a single type of structure either, just use a magic number at the start of the structure to identify its type and then go crazy, in a awkward way because you can just do only so much with the language (for example, no casting).
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:20 pm
by s0ula55a551n
Thanks for all the pointers ( pun intended) people.
I was originally using @ to return address, but found that returning the variable name produced the same results.
Of course I really didn't thin about the fact that it would be removed from memory once the module had completed, especially as the manual told me tat kind of.
Is there a better version of the help. Have seen quite a few commands either in others code or by the auto-complete that have no entries in the help files
thanks all
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:23 pm
by s0ula55a551n
sys64802 wrote:I suggest you to read well the manual about pointers and structures, and to do more experiments with them and some code simpler than this one because a lot of things here makes no sense whatsoever.
Start simpler.
To answer your question, you are creating a structure newEnemy of type object on the stack of the procedure createEnemy().
Then you return the base address of that structure and exit the procedure.
Upon leaving, the space on the stack for that structure and any other local variable is freed.
Then you try to access an element from that structure which does not exists anymore by coping its defunct address to a structured pointer of type object.
So you get garbage.
Other suggestions: use EnableExplicit, use Define or Global to define a var instead of throwing its name.type in the middle of the source (IMO the compiler should complain there because it has no meaning), and use @ when passing the address of a structure (it could help you in the future).
Yes, PB cannot return a structure, you can implement e mechanism to copy back a structure in a passed buffer preallocated by the caller if you like, see CopyStructure() and its family, it's equivalent of what many languages returning structures do, only there is invisible.
And yes, to dynamically allocate an "object" you have to allocate it by yourself like infratec said.
edit: pasted something in the wrong place...
Thanks for all the suggestions
Trying to avoid globals and such. I could do things simpler and its my fault for trying to enforce good encapsulation etc on BASIC
Hadn't noticed allocate memory and the such thanks.
Might post my simpler code when I had more of a play around
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:30 pm
by sys64802
s0ula55a551n wrote:
Is there a better version of the help. Have seen quite a few commands either in others code or by the auto-complete that have no entries in the help files
No, there is not, if you exclude the forum
There is a book, not updated
http://www.purebasic.fr/english/viewtop ... 14&t=37059
The help afaik include all the PB commands, maybe not all are indexed but if you read all the help at least once you will find them.
Maybe the other commands you saw are API functions ? Ending with "_" ?
In that case they are not documented and you have to refer to the OS documentation.
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:36 pm
by s0ula55a551n
infratec wrote:Maybe something like this:
Thanks, put my on the correct lines. Can't believe hit was a scoping error
so this works much better now. Thanks
Code: Select all
Module obj_Create
Procedure.i createEnemy(type)
Protected *newEnemy.object
*newEnemy = AllocateStructure(object)
*newEnemy\curr_x_dir = 44
*newEnemy\enemy = type
Debug "contents of new copied obj in proc " + *newEnemy\curr_x_dir
ProcedureReturn *newEnemy
EndProcedure
EndModule
NewList *testPointers.obj_Create::object()
AddElement(*testPointers())
*testPointers() = obj_Create::createEnemy(obj_Create::#Goblin)
Debug *testPointers()\curr_x_dir
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 9:52 pm
by s0ula55a551n
Easy enough then to destroy using a method on the module
Take it this is not mad and will free the memory properly ?
Code: Select all
Procedure createEnemy(type)
Protected *newEnemy.object
*newEnemy = AllocateStructure(object)
With *newEnemy
\curr_x_dir = 44
EndWith
ProcedureReturn *newEnemy
EndProcedure
Procedure destroyObject(*object)
FreeStructure(*object)
EndProcedure
Re: Pointers, modules and structure
Posted: Fri Jan 08, 2016 10:50 pm
by infratec
That's the way to go.