Linked list pointer trouble

Just starting out? Need help? Post your questions and find answers here.
JJ
User
User
Posts: 23
Joined: Fri Feb 16, 2007 12:41 am
Location: Paris, France

Linked list pointer trouble

Post by JJ »

Hi,

I study the answer made to Uvosa by Fred (http://www.purebasic.fr/english/viewtop ... inked+list) and I believe that a trouble exist in the PB 4.02 with linked list and pointer.

Code: Select all

Structure TestStruct 
  Text.b[10000] 
EndStructure 

Procedure SetStructList(val, *Test.TestStruct()) 
  AddElement(*Test()) 
  ; Uncomment the following line(s) to see memory reserved twiced (use the task manager to see the trouble)
  ; 100 MB reserved when the next line is commented, and it seems normal
  ; 200 MB reserved when the next line is uncomment, it's the problem
  ;  *Test() = AllocateMemory(SizeOf(TestStruct))
  ; UnCommented lines produce "Pointer is null." error since PB v4.02, if the previous line is commented
  ;  *Test()\Text[0]=val
EndProcedure 

Procedure test()
  NewList toto.TestStruct()
  
  CallDebugger
  For i=1 To 10000
    SetStructList(i%$FF, toto.TestStruct())
  Next

  CallDebugger
  ClearList(toto()) 
EndProcedure
 
;- Main 
test()
End
Usually if only pointer is reserved for each Addelement(), we must find near 40000 bytes reserved (if all the lines are commented like example) but we have 100MB. It seems that the memory is allocated but the pointer returned is always NULL.

Thanks in advance for your help.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

hi.

if you want to post quicklinks (without URL-tags) you have to leave spaces around them.
( http://www.purebasic.fr/english/viewtop ... inked+list )


I don't get the point really... not your's but the code's
there seem to be some problems, but where is it exactly....?
my main problem is, that I never used pointer notations to reserve elements.

the memory usage seems to be clear for me.
you add 10000 elements that need 10008 bytes each and surely get them.
if you alter the pointer afterwards to some new allocated memory,
of course the memory usage should double.

but I don't get the point why the pointer to the old allocated mem should be NULL....

maybe the mem is allocated but the pointer to it isn't connected correctly?

additionally just for interest:
what is the advantage in this pointer-notation for using AddElement anyways?
I would use a normal call of AddElement, you can use a pointer access after that in every case....

it's just that...
if the basic idea to use AddElement with a pointer was wrong,
then it's not a bug of PB but a bug in this form of programming....
oh... and have a nice day.
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

Post by pcfreak »

even if you define the procedure parameter as pointer, it is handled as linkedlist, thus you can't use it as pointer.

Code: Select all

Structure TestStruct
  Text.b[10000]
EndStructure

Procedure SetStructList(val, *Test.TestStruct())
  AddElement(*Test())
  ; Uncomment the following line(s) to see memory reserved twiced (use the task manager to see the trouble)
  ; 100 MB reserved when the next line is commented, and it seems normal
  ; 200 MB reserved when the next line is uncomment, it's the problem
  ; *Test() = AllocateMemory(SizeOf(TestStruct))
  ; UnCommented lines produce "Pointer is null." error since PB v4.02, if the previous line is commented
  *toto.TestStruct=@*Test()
  *toto\Text[0]=val
EndProcedure

Procedure test()
  NewList toto.TestStruct()
 
  CallDebugger
  For i=1 To 10000
    SetStructList(i%$FF, toto.TestStruct())
  Next

  CallDebugger
  ClearList(toto())
EndProcedure
 
;- Main
test()
End
either you use the pointer returned from AddElement (contains the pointer to the element before and after) or you get it directly from the element as shown above. this way you don't have to care about the internal linkedlist management of purebasic. either way the 10000 bytes for the structure are reserved after the AddElement command, hence it grows even more if you allocate it every time additional to it. i don't know if it can be considered as memory leak that purebasic doesn't frees the memory if the pointer gets changed. well, seems a bit confusing how purebasic handles linkedlists passed as pointer. in one point it's as if it wasn't passed as pointer and in one way it's like a pointer ('cause you can't just change the element right after adding a new element, but needs to take the pointer of it)
it's just not obviously how this has to be handles correctly, so i guess it's a problem for the help file (partly for purebasic itself, 'cause it's just too confusing). the more you think about it the less you get, thus that's it from me :?
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

I don't understand a thing of what you're saying. And what I do understand is wrong.

Linked lists are ALWAYS passed as a pointer to the list.
even if you define the procedure parameter as pointer, it is handled as linkedlist, thus you can't use it as pointer.
You haven't declared a pointer parameter, you have declared a linked list of pointers as the parameter.
freak
PureBasic Team
PureBasic Team
Posts: 5944
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Of course the memory usage grows. You call AllocateMemory() 10000 times, but not one FreeMemory()

pcfreak:
I think you misunderstand this: *Test.TestStruct() defines a linkedlist OF pointers.
So the elements in the list are pointers, not the list itself.

When you call AddElement() on such a list, you get a new empty pointer, just like when defining a variable *Pointer.
You have to assign some memory location to it in order to work with it.

btw, linkedlists as procedure parameters are always passed by reference.
quidquid Latine dictum sit altum videtur
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

Post by pcfreak »

freak wrote: pcfreak:
I think you misunderstand this: *Test.TestStruct() defines a linkedlist OF pointers.
So the elements in the list are pointers, not the list itself.

When you call AddElement() on such a list, you get a new empty pointer, just like when defining a variable *Pointer.
You have to assign some memory location to it in order to work with it.
but why are for each element 10000 bytes reserved when it gets created? it 'seems' as if not a pointer but the whole structure gets created, as in my example you can even access this structure. sorry, but i just don't get the system behind that. if i want a list of pointers that can be used on structured memory field by field i would declare it as it was in the example, but that shouldn't allocate the memory for the structure but only a pointer for such. :?
freak
PureBasic Team
PureBasic Team
Posts: 5944
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Code: Select all

NewList toto.TestStruct() 
You define the original list not as a pointer. This is the problem.
quidquid Latine dictum sit altum videtur
JJ
User
User
Posts: 23
Joined: Fri Feb 16, 2007 12:41 am
Location: Paris, France

Post by JJ »

Kaeru Gaman wrote:hi.

if you want to post quicklinks (without URL-tags) you have to leave spaces around them.
( http://www.purebasic.fr/english/viewtop ... inked+list )


I don't get the point really... not your's but the code's
there seem to be some problems, but where is it exactly....?
my main problem is, that I never used pointer notations to reserve elements.

the memory usage seems to be clear for me.
you add 10000 elements that need 10008 bytes each and surely get them.
if you alter the pointer afterwards to some new allocated memory,
of course the memory usage should double.

but I don't get the point why the pointer to the old allocated mem should be NULL....

maybe the mem is allocated but the pointer to it isn't connected correctly?
It's what I think!
additionally just for interest:
what is the advantage in this pointer-notation for using AddElement anyways?
I use it in recursive code, who a linked list is created in each entry call, and i use the pointer on the linked list to work with it.
I would use a normal call of AddElement, you can use a pointer access after that in every case....

it's just that...
if the basic idea to use AddElement with a pointer was wrong,
then it's not a bug of PB but a bug in this form of programming....
JJ
User
User
Posts: 23
Joined: Fri Feb 16, 2007 12:41 am
Location: Paris, France

Post by JJ »

freak wrote:Of course the memory usage grows. You call AllocateMemory() 10000 times, but not one FreeMemory()

pcfreak:
I think you misunderstand this: *Test.TestStruct() defines a linkedlist OF pointers.
So the elements in the list are pointers, not the list itself.

When you call AddElement() on such a list, you get a new empty pointer, just like when defining a variable *Pointer.
You have to assign some memory location to it in order to work with it.

btw, linkedlists as procedure parameters are always passed by reference.
I agree with you, but if you uncommented the line:

*Test()\Text[0]=val

You will see that in PB 4.01 everything works fine, the linked list is created correctly and you can write the 10000 byte without any problem for each element. And if you do that with PB 4.02, you have an error "pointer null".

In PB4.02 you see the memory reserved growing and never freeing. Then if the linked list contains only pointer, why Pure reserved on each call 10000 bytes and not only the 8 bytes for the pointers.

Second point why the memory are never free when the procedure returns. The allocation is manage dynamiquely by the core of PB, then how could you free the memory allocated by Pure? (leave all the line commented for the test, and try to free the memory)

I didn't verify if in PB 4.01 the memory is properly freeing, I'll make the test when I'm come back from vacation.

PS: I'm in vacation tonight so, i will continue the discussion next Saturday.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

@JJ
This is how you should be performing the actions you needed:

Code: Select all

Structure TestStruct
  Text.b[10000]
EndStructure

Procedure SetStructList(val, Test.TestStruct())
  AddElement(Test())
  ; Uncomment the following line(s) to see memory reserved twiced (use the task manager to see the trouble)
  ; 100 MB reserved when the next line is commented, and it seems normal
  ; 200 MB reserved when the next line is uncomment, it's the problem
  ; *Test() = AllocateMemory(SizeOf(TestStruct))
  ; UnCommented lines produce "Pointer is null." error since PB v4.02, if the previous line is commented
  Test()\Text[0]=val
EndProcedure

Procedure Test()
  NewList toto.TestStruct()
  
  CallDebugger
  For I=1 To 10000
    SetStructList(I%$FF, toto.TestStruct())
  Next
  
  CallDebugger
  ClearList(toto())
EndProcedure

;- Main
Test()
End 
Your procedure SetStructList() is passed a linked list by reference which is not the same as passing a pointer to it. This means the procedure should declare the variable as a linked list type. It should address it the same as a linked list.

The only change necessary to make the correction is to remove the "*" from your variable so that it is not confused with a pointer to a structure (not a linked list as you desired), see comment below. All the comments in SetStructList() are now irrelevant.

In the code you presented it seems the compiler can't tell if it should treat the variable *Test().TestStruct() as a pointer to a linked list, or a generic pointer, or perhaps a pointer to a structure (who knows, maybe Fred?:)). This is evident from the code you first presented. I don't quite understand it but, if you checked the value of the pointer while in the procedure it points to a structure of TestStruct. It can access it but, it seems to treat every element of the structure as a pointer also. The two interpretations run into conflict. For instance, it can't acess things in the structure that have a value of zero and says they have a null pointer. Also, when you reserve memory space for a structure and assign it to the pointer with

Code: Select all

*Test() = AllocateMemory(SizeOf(TestStruct))
it assigns the value of the memory pointer (a Long) to the location pointed to by the structure. I think there is a bug or undesirable feature in the way this value is assigned. It ignores the "structure" format and simply stores the 32 bit value starting at the first memory location. By viewing the value of the structure after this assignment it is shows that the first four entries in the array of bytes were changed. THIS is what I would think is unexpected and an issue to be resolved or avoided.

As stated earlier though, YOUR problem is the misuse of variable types. If you got away with it in the past your luck seems to have run out.
JJ
User
User
Posts: 23
Joined: Fri Feb 16, 2007 12:41 am
Location: Paris, France

Post by JJ »

Demivec wrote:@JJ
This is how you should be performing the actions you needed:

Code: Select all

Structure TestStruct
  Text.b[10000]
EndStructure

Procedure SetStructList(val, Test.TestStruct())
  AddElement(Test())
  ; Uncomment the following line(s) to see memory reserved twiced (use the task manager to see the trouble)
  ; 100 MB reserved when the next line is commented, and it seems normal
  ; 200 MB reserved when the next line is uncomment, it's the problem
  ; *Test() = AllocateMemory(SizeOf(TestStruct))
  ; UnCommented lines produce "Pointer is null." error since PB v4.02, if the previous line is commented
  Test()\Text[0]=val
EndProcedure

Procedure Test()
  NewList toto.TestStruct()
  
  CallDebugger
  For I=1 To 10000
    SetStructList(I%$FF, toto.TestStruct())
  Next
  
  CallDebugger
  ClearList(toto())
EndProcedure

;- Main
Test()
End 
Your procedure SetStructList() is passed a linked list by reference which is not the same as passing a pointer to it. This means the procedure should declare the variable as a linked list type. It should address it the same as a linked list.

The only change necessary to make the correction is to remove the "*" from your variable so that it is not confused with a pointer to a structure (not a linked list as you desired), see comment below. All the comments in SetStructList() are now irrelevant.

In the code you presented it seems the compiler can't tell if it should treat the variable *Test().TestStruct() as a pointer to a linked list, or a generic pointer, or perhaps a pointer to a structure (who knows, maybe Fred?:)). This is evident from the code you first presented. I don't quite understand it but, if you checked the value of the pointer while in the procedure it points to a structure of TestStruct. It can access it but, it seems to treat every element of the structure as a pointer also. The two interpretations run into conflict. For instance, it can't acess things in the structure that have a value of zero and says they have a null pointer. Also, when you reserve memory space for a structure and assign it to the pointer with

Code: Select all

*Test() = AllocateMemory(SizeOf(TestStruct))
it assigns the value of the memory pointer (a Long) to the location pointed to by the structure. I think there is a bug or undesirable feature in the way this value is assigned. It ignores the "structure" format and simply stores the 32 bit value starting at the first memory location. By viewing the value of the structure after this assignment it is shows that the first four entries in the array of bytes were changed. THIS is what I would think is unexpected and an issue to be resolved or avoided.

As stated earlier though, YOUR problem is the misuse of variable types. If you got away with it in the past your luck seems to have run out.
Thank's Demivec for your time and help, you right, now everything is OK. But I think that in the <PB4.01 they was a bug with this type of pointer linkedlist declaration.
Post Reply