Page 1 of 1

PokeS() vs *String\s

Posted: Tue Feb 25, 2025 9:36 am
by Justin
Is it legal to do this or are both options wrong?

Code: Select all

EnableExplicit

Procedure test(st.i)
	Protected.String *s
	
	*s = @st
	*s\s = "foo" ;OK?
	
	;PokeS(st, "foo") ;Wrong?
EndProcedure

Define.s st

st = ""

test(@st)

Debug st

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 10:08 am
by infratec
Enable Purifier and set granularity to 1, 1, 1, 1

Then you should see that both is wrong.
You don't have the place to store the string.

You can do

Code: Select all

st = space(512)

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 10:19 am
by STARGÅTE
Both codes are wrong.

With PokeS(), you did not allocate the additional needed memory, which causes an IMA.
With *s\s you write a new string and the memory address could change, so the main string is not affacted:

Code: Select all

EnableExplicit

Procedure test(st.i)
	Protected.String *s
	
	*s = @st
	*s\s = "Hello World"
	Debug "Local: " + @*s\s

	;PokeS(st, "foo") ;Wrong?
EndProcedure


Define.s st

st = "123"
Debug "Main: " + @st
test(@st)
Debug "Main: " + @st

Debug st
You should use the String-Structure in the Main-Code and Procedure:

Code: Select all

Procedure test(*s.String)
	*s\s = "Hello World"
EndProcedure

Define MyString.String

MyString\s = "123"
test(@MyString)
Debug MyString\s

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 12:06 pm
by SMaag
@justin
Why you want to to this?

If you want to speed up String-Parameters in Procedures - if you don't want PB to copy the String!

The solution is Prototype your Procedure. Then PureBasic pass the StringPointer directly and do not make a copy
of the String.

here is an example for

Code: Select all

EnableExplicit

Prototype.i ReplaceChar(String$, cSearch.c, cReplace.c) ; ProtoType-Function for ReplaceChar
Global ReplaceChar.ReplaceChar                          ; define Prototype-Handler for CountChar

Procedure.i _ReplaceChar(*String, cSearch.c, cReplace.c)
           
  Protected *char.Character   ; Pointer to a virutal Char-Struct
  Protected N
  
  *char = *String         
  If *char    
    While *char\c               ; until end of String
      If *char\c =  cSearch
        *char\c = cReplace    ; replace the Char
        N + 1
      EndIf
      *char + SizeOf(Character)   ; Index to next Char
    Wend
  EndIf
  ProcedureReturn N     
EndProcedure
ReplaceChar = @_ReplaceChar()     ; Bind ProcedureAdress to the PrototypeHandler

Define Txt$="1234561.123456111"

Debug Txt$
ReplaceChar(Txt$, '1', 'A')   ; Txt$ is passed as @Txt$
Debug Txt$

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 12:44 pm
by Justin
So both are wrong, thanks!

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 2:49 pm
by AZJIO
Justin wrote: Tue Feb 25, 2025 9:36 am

Code: Select all

test(@st)
If you pass the pointer, then you must accept it as a pointer

Code: Select all

Procedure test(*st)
Or pointer to the structure

Code: Select all

Procedure test(*st.Integer)
Justin wrote: Tue Feb 25, 2025 9:36 am

Code: Select all

*s = @st
Here, "st" is a pointer, and you again take the pointer from it. You don't have a string in the pointer, but a number pointer.

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 3:33 pm
by STARGÅTE
AZJIO wrote: Tue Feb 25, 2025 2:49 pm
Justin wrote: Tue Feb 25, 2025 9:36 am

Code: Select all

*s = @st
Here, "st" is a pointer, and you again take the pointer from it. You don't have a string in the pointer, but a number pointer.
This part of Justin's code is right.
"st" is a pointer (integer) and you have to receive its pointer as well to take it over to the String-Structure .String, because here you have a Pointer to a Structure its first field is a pointer to a string.

Code: Select all

Define String.s  = "Hello World"  ; The string
Define *Pointer  = @String        ; Pointer to the String content itself
Define *StringStructure.String = @*Pointer  ; Pointer to the String-Pointer

Debug *StringStructure\s
However, this way is read-only. During write, you would change the string location in memory, which is not reflected back to String.s

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 3:43 pm
by AZJIO
STARGÅTE
Yes, you're right, I forgot that lately I've been using *c.Character pointers, where you need to take a pointer 1 time.

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 3:56 pm
by AZJIO
I've experimented with such a feature before. If you are passing a pointer instead of a structure, then you cannot increase the length of the string, since it is declared in the outer scope. If the author of the topic has passed an empty string and then writes data to it, then he will simply break the memory.

Code: Select all

Procedure.s TrimLeft(*a, n)
	Protected *p.string = @*a
	*p\s = Right(*p\s, Len(*p\s) - n)
EndProcedure
tmp$ = "Hello world"
TrimLeft(@tmp$, 3)
Debug tmp$
Instead of test(@st), you should use:

Code: Select all

Define st.String
test(@st)

Re: PokeS() vs *String\s

Posted: Tue Feb 25, 2025 4:01 pm
by STARGÅTE
AZJIO wrote: Tue Feb 25, 2025 3:56 pm If you are passing a pointer instead of a structure, then you cannot increase the length of the string, since it is declared in the outer scope.
Exactly.