Page 1 of 1

Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 4:45 am
by TheAutomator
I have a few questions on pointers as I'm trying to learn them bit by bit.
To do so while simultaneously solving a little problem I encounter now and then I started a little learning project:

"Use pointers to store variables as variants"

Code: Select all

; var = 10 (vbscript syntax used as example)

*variant = AllocateMemory(8)
PokeI(*variant, 10)

Debug PeekI(*variant)

; now set var to string: var = "test"

*variant = ReAllocateMemory(*variant, 4) ; why does less work and should i include the string terminator character in the count?
PokeS(*variant, "test")

Debug PeekS(*variant)
I'm also planning to create a linked list type of object, it will use a hash table filled with pointers to the actual values stored in memory (build upon a previous post).

I don't really get how structures are valid pointer types tho? What does a structure look like in memory behind the scenes?

Many thanks for any help!

Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 7:54 am
by idle

Code: Select all


Structure PB_ANY ;this is the equivalent of a variant  
  type.b         ;it has a runtime type  
  StructureUnion   ; structure union means it's one of the types in the union, it's size is the largest type  
    a.a
    b.b
    c.c
    w.w
    u.u
    l.l
    i.i
    f.f
    d.d
    q.q
    *p 
  EndStructureUnion 
  s.s                            ;we can't put strings in the union but you can use the pointer 
EndStructure 


Global var1.PB_ANY    ;make two varients 
Global var2.PB_ANY

var1\type = #PB_Integer   ;set var 1 to an integer 
var1\i = 1232345  

var2\type = #PB_Double  ;set var2 to a double 
var2\d = #PI 

Global *ptr.PB_any    ;make a pointer to a pb_any 

*ptr = @var1  ;deref var1 its a interger 

Debug *ptr\i  

*ptr = @var2  ;defref var2 it's a double 

Debug *ptr\d 



Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 8:29 am
by IceSoft
@fred
I think a 'void' pointer is a good idea (like *void in C language, which is a placeholder for 'all' pointer types)
e.g;

Code: Select all

Global *ptr.PB_any 
PB_any is like

Code: Select all

 void* ptr =  nullptr; 
with C language

Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 10:27 am
by juergenkulow
Pointers and memory access
Structures

Code: Select all

; Pointer to a Structure with List
Structure Person
  Name$
  List Friends$()
  Age.l
EndStructure
  
*ptr.Person=AllocateStructure(Person)
*ptr\Name$="Thomas"
AddElement(*ptr\Friends$())
*ptr\Friends$()="Martin"
*ptr\Age=9
Debug Hex(*ptr) 
ShowMemoryViewer(*ptr,SizeOf(Person))
; 000000000124F2C0  20 70 10 01 00 00 00 00 78 DA 26 01 00 00 00 00   p......xÚ&.....
; 000000000124F2D0  08 5B 21 01 00 00 00 00 09 00 00 00              .[!.........
MessageRequester("","")
Debug Hex(@*ptr\Name$)
Debug *ptr\Name$
ShowMemoryViewer(@*ptr\Name$,14)
; 0000000001107020  54 00 68 00 6F 00 6D 00 61 00 73 00 00 00        T.h.o.m.a.s...
MessageRequester("","")
Debug Hex(@*ptr\Friends$())
Debug *ptr\Friends$()
*p.Integer=@*ptr\Friends$()
ShowMemoryViewer(*p\i,14)
; 000000000110A4E0  4D 00 61 00 72 00 74 00 69 00 6E 00 00 00        M.a.r.t.i.n...
; 124F2C0
; 1107020
; Thomas
; 1215B18
; Martin

Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 12:14 pm
by SMaag

Code: Select all

Structure TUPtr  ; Universal Pointer (see PurePasic IDE Common.pb Structrue PTR)
    StructureUnion
      a.a[0]    ; ASCII   : 8 Bit unsigned  [0..255] 
      b.b[0]    ; BYTE    : 8 Bit signed    [-128..127]
      c.c[0]    ; CAHR    : 2 Byte unsigned [0..65535]
      w.w[0]    ; WORD    : 2 Byte signed   [-32768..32767]
      u.u[0]    ; UNICODE : 2 Byte unsigned [0..65535]
      l.l[0]    ; LONG    : 4 Byte signed   [-2147483648..2147483647]
      f.f[0]    ; FLOAT   : 4 Byte
      q.q[0]    ; QUAD    : 8 Byte signed   [-9223372036854775808..9223372036854775807]
      d.d[0]    ; DOUBLE  : 8 Byte float    
      i.i[0]    ; INTEGER : 4 or 8 Byte INT, depending on System
      *p.TUPtr[0] ; Pointer for TUPtr (it's possible and it's done in PB-IDE Source) This can be used as a PointerPointer like the C **Pointer
    EndStructureUnion
  EndStructure
  
  *variant = AllocateMemory(8)
  *uPtr.TUPtr = *variant

  PokeI(*variant, 10)
  Debug PeekI(*variant)
  
  ; now the same with Universal Pointer
  ; The trick wiht the Array[0] give us a StructureUnion like access
  *uptr\i[0] = 11
  Debug *uptr\i[0]
  
  *uptr\i[0] + 1
  Debug *uptr\i[0]
  

Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 12:26 pm
by SMaag
other Example: Direct access to strings as Array of Char

Code: Select all

Structure pChar
  a.a[0]
  c.c[0]
EndStructure

*pChar.pChar

str$="I am a String"
*pChar = @str$

For I = 0 To Len(str$)-1
  Debug Chr(*pChar\c[I])  + " : " +  *pChar\c[I]
Next



Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 4:01 pm
by skywalk
I don't use this often, but it does help me when looking up or choosing datatypes.

Code: Select all

Structure ScanAllTypes  ;-!PB Datatypes
  ; Allows 1 Define for all datatypes to be scanned.
  ; Define *p.ScanAllTypes = @somevariable or *somememory
  ; Consider as a StructureUnion. Takes no memory and overflow is not checked.
  ; Ex. *p\d[i] ; 'i' can be incremented in a loop without compiler error.
  ;          ; Type,   Bytes,  Min,                     Max,                     C Type
  b.b[0]     ; Byte,       1, -128,                     127,                     char, bool(C++)
  a.a[0]     ; Ascii,      1,  0,                       255,                     unsigned char, UCHAR, BYTE
  c.c[0]     ; Character,  2,  0,                       65535,                   unsigned short, USHORT
  u.u[0]     ; Unicode,    2,  0,                       65535,                   unsigned short, USHORT
  w.w[0]     ; Word,       2, -32768,                   32767,                   short, VB6 integer
  l.l[0]     ; Long,       4, -2147483648,              2147483647,              long, int (long & $FFFFFFFF = unsigned)
  ;;ul.ul[0] ; ULong,      4,  0,                       4294967295,              unsigned long, unsigned int, DWORD(C++)
  i.i[0]     ; Integer,    4, -2147483648,              2147483647,              long, int(x86 or 32-bit),sizeof*
  ;i.i[0]    ; Integer,    8, -9223372036854775808,     9223372036854775807,     long long(x64 or 64-bit),sizeof*
  q.q[0]     ; Quad,       8, -9223372036854775808,     9223372036854775807,     long long
  ;;uq.uq[0] ; UQuad,      8,  0,                       18446744073709551615,    unsigned long long, ULONGLONG
  f.f[0]     ; Float,      4,           -1.175494e-38,            3.402823e+38,  float      (6 decimal places)
  d.d[0]     ; Double,     8, -2.2250738585072013e-308, 1.7976931348623157e+308, double     (15 decimal places)
  ;;ld.ld[0] ; LDouble,   10,                -3.4e-4932,               1.1e+4932,long double(19 decimal places)
  ;;s.s      ; String$,    2/char + 2 for chr(0),       ,                        wchar_t, TCHAR
  ;s.s[0]    ; FAIL, -> *p = @x$, *p\s[0] = IMA ERROR.
  ; STRINGS require 2 elements for simple string and arrays/maps of string.
  s.s{1}[0]  ; {FixedLen}, 2/char,                      ,                        char *, char var[] <-- Convert to Ascii
  ;s.s[0]    ; OK,   -> *p = @x$,   *p\s[1],  *p\s[2],  etc.
  ss.s[0]    ; Scan String array.
  ;ss.s[0]   ; OK,   -> *p = @x$(), *p\ss[1], *p\ss[2], etc.
EndStructure
CompilerIf 1
  Define *p.ScanAllTypes
  Define *p2.ScanAllTypes
  Dim a$(2)
  Define.s s$ = "xyz"
  a$(0) = s$ + "0"
  a$(1) = s$ + "1"
  a$(2) = s$ + "2"
  NewMap mapa$(16)
  mapa$("0") = "map0"
  mapa$("1") = "map1"
  mapa$("2") = "map2"
  NewList lla$()
  AddElement(lla$())
  lla$() = "ll0"
  AddElement(lla$())
  lla$() = "ll1"
  AddElement(lla$())
  lla$() = "ll2"
  Debug "-- String --"
  *p = @s$        ; *ptr to string, use *p\s[]
  Debug *p\s[0]   
  Debug *p\s[1]
  Debug *p\s[2]
  Debug "-- Array --"
  *p = @a$()      ; *ptr to string array(), use *p\ss[]
  *p2 = @*p\ss[0]
  Debug *p\ss[0] 
  Debug *p2\s[0] + "0"
  Debug *p2\s[1] + "1"
  Debug *p2\s[2] + "2"
  Debug *p\ss[1]
  Debug *p\ss[2]
  Debug "-- List --"
  FirstElement(lla$())
  *p = @lla$(); *ptr to lla$(), use *p\ss[]
  Debug *p\ss[0]
  Debug "-- Map --"
  *p = @mapa$("x"); *ptr to mapa$(), use *p\ss[]
  Debug *p\ss[0] + "mapa$"
  Debug *p\ss[1] + "mapa$"
  Debug *p\ss[2] + "mapa$"
  *p = @mapa$("y"); *ptr to mapa$(), use *p\ss[]
  Debug *p\ss[0] + "mapa$"
  Debug *p\ss[1] + "mapa$"
  Debug *p\ss[2] + "mapa$"
CompilerEndIf

Re: Understanding Pointers Completely!

Posted: Sat Feb 11, 2023 6:23 pm
by spikey
TheAutomator wrote: Sat Feb 11, 2023 4:45 amWhy does less work?
It only works in this particular instance because it's simple. In others you would cause a memory corruption problem because you're actually creating a buffer overrun error. This is because PB uses Unicode encoding which require two bytes of memory for each character. So your four character string requires eight bytes to store in memory plus two for the terminating zeros. If you enable the Purifier in the compiler options and set the granularity to every line like this an overflow error will be reported by the debugger, see below. The StringByteLength instruction can be used to derive correct buffer sizes for strings, see https://www.purebasic.com/documentation ... ength.html

Code: Select all

PurifierGranularity(1, 1, 1, 1)

; var = 10 (vbscript syntax used as example)

*variant = AllocateMemory(8)
PokeI(*variant, 10)

Debug PeekI(*variant)

; now set var to string: var = "test"

*variant = ReAllocateMemory(*variant, 4) ; why does less work and should i include the string terminator character in the count?
PokeS(*variant, "test")

Debug PeekS(*variant)
TheAutomator wrote: Sat Feb 11, 2023 4:45 amShould I include the string terminator character in the count?
Yes, you should have done in this instance because you didn't specify the #PB_String_NoZero flag to PokeS so it will default to including the terminators.
TheAutomator wrote: Sat Feb 11, 2023 4:45 amI don't really get how structures are valid pointer types tho?
It's a nomenclature used in the IDE, compiler and debugger. These applications make a note of the type and infer information from it later on. When you create a typed pointer, it contains the memory address of the first byte of the data 'in the structure', just as a pointer to a memory buffer contains the address of the first byte of the buffer. The IDE (et al) are aware of the structured nature of the pointer from the note and provide additional context information to the programmer. So, for example, autocomplete can present the names of the members, x and y, when I type *ThisPoint\ in this example. (POINT being a structure pre-defined in the Windows API headers and included in PB).

Code: Select all

; POINT is predefined like this
; Structure POINT
;  x.l
;  y.l
; EndStructure
Define.POINT *ThisPoint
*ThisPoint = AllocateStructure(POINT)
Debug SizeOf(POINT)
*ThisPoint\x = 10
*ThisPoint\y = 20
ShowMemoryViewer(*ThisPoint, 8)
You should be able to see the layout in the memory viewer when this example runs. You can determine the size of a structure with the SizeOf() compiler function and the exact position of a particular member with OffsetOf(), see https://www.purebasic.com/documentation ... tions.html. The actual values in this example only require a single byte to represent their content but each one has been allocated 4 bytes, the SizeOf(LONG), so the SizeOf(POINT), the full structure, is 8 bytes.
TheAutomator wrote: Sat Feb 11, 2023 4:45 amWhat does a structure look like in memory behind the scenes?
In actual memory at runtime it is laid out as a sequential collection of bytes starting from the address in the pointer and running continuously for the length of the size of the structure. The precise layout depends on the types of the members, if the 'Align' directive is used in the structure definition and if the structure contains strings. Alignments may cause empty bytes to be included in the layout if members must be presented in specific positions (for example to conform to OS API function calls). When a string is included in a structure a pointer to the string is placed in the layout and the string content itself is laid out elsewhere in memory.

Re: Understanding Pointers Completely!

Posted: Sun Feb 12, 2023 1:27 am
by TheAutomator
Wow, a lot of reply's, good! :p

So it's not as simple as allocating 4 (or 8) bites to a pointer for an integer and afterwards reallocating to the string size?

Also, using structure union doesn't allow strings as types and if you use structure union it's gonna use more memory than needed: "always uses the largest size of the structure subtypes"..?

Just doing reallocate stringsize()... is not a good idea?

Re: Understanding Pointers Completely!

Posted: Sun Feb 12, 2023 5:08 am
by mk-soft
The string management is done internally by PB. A variable of type string is already a pointer to the string. Extending or creating new string memory is therefore done by PB. Thus, the pointer on the string can also change if necessary.

Re: Understanding Pointers Completely!

Posted: Mon Feb 13, 2023 2:11 pm
by TheAutomator
I see, that's why it's put inside a struct as a normal variable :)

So structure unions always pick the biggest value to make space for, even if you just want to store for example a bite?

Maybe I'm just better of not using pointers and memory allocation to store variables.. I'm looking for a simple way to store variables that i get from a script file, I'm making some sort of interpreter.

Re: Understanding Pointers Completely!

Posted: Mon Feb 13, 2023 3:18 pm
by mk-soft
The use of pointers, once understood, simplifies many things. Structures are also very important, instead of storing everything in individual variables.
So don't give up.

Re: Understanding Pointers Completely!

Posted: Fri Mar 03, 2023 7:38 pm
by TheAutomator
I don't want to but reading all the reply's it shows you have to know a lot more than only "a pointer is a variable holding an address"..
You basically have to know the inner workings of the programming language you use too and that's not like a quick read trough the manual if you ask me :(

Small recap of what i learned in this topic already:
- strings are already pointers in pb, no "string" type needed to point to their memory
- structures are useful for allocating memory but always take up the maximum amount of space declared if you use structure-union
- allocating space can be dangerous if you miscalculate the size