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 :mrgreen:

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
:D

That's the way to go.