Announcement

Collapse
No announcement yet.

Problems w/ String Pointers

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problems w/ String Pointers

    Now I'm lost with pointers to a string.

    PB helpfile contains following code snippet as an example

    Code:
    SUB Lower(zStr AS STRING)
      DIM s AS STRING PTR, i AS INTEGER
      s = VARPTR(zStr)
      FOR i = 1 TO LEN(zStr)
        IF @s = "A" THEN @s = "a"
        INCR s
      NEXT
    END SUB
    When I started to get some problems in a similar situation, I copied the sample above to my program and I think it worked for a while - can't be sure anymore. Now it only GPF's for me, no matter what I do (restart Windows, reboot the machine, use fixed lenght or null terminated strings etc.)

    Does anybody know what is wrong now?

    I have attached a small compilable sample which on my system GPF's.

    I have thought that following is true

    Code:
      VARPTR(s) s=s+15  @s=P      
         |              |
         v              v
    s = "ABCDEFGHIJKLMNOP"
         0123456789012345
    	           111111
    but seems that I'm wrong because if I look the execution of Sub above, it increments S in steps of 4 (causing the code to point to some place illegal?).

    TIA
    Lasse Rantanen
    [email protected]

    Code:
    $COMPILE EXE
    #INCLUDE "WIN32API.INC"
     
    %LOWER   = 1000
    %CANCEL  = 1001
    %LABEL1  = 1002
     
    DECLARE CALLBACK FUNCTION TestDlgProc
    DECLARE SUB Lower(zStr AS STRING)
     
    GLOBAL hDlg  AS LONG
     
    '==============================================================================
    FUNCTION WINMAIN (BYVAL CurInst AS LONG, _
                      BYVAL PrvInst AS LONG, _
                      CmdLine AS ASCIIZ PTR, _
                      BYVAL CmdShow AS LONG) EXPORT AS LONG
     
        DIALOG NEW  0, "String Test", , , 140, 80, %WS_CAPTION , TO hDlg
        CONTROL ADD LABEL, hDlg, %LABEL1, "AbbAaBBa", 5, 10, 130, 28
        CONTROL ADD BUTTON, hDlg, %LOWER, "Lower", 5, 60, 60, 14
        CONTROL ADD BUTTON, hDlg, %CANCEL, "Cancel", 75, 60, 60, 14
        DIALOG SHOW MODAL hDlg, CALL TestDlgProc
     
    END FUNCTION
     
    '==============================================================================
    CALLBACK FUNCTION TestDlgProc
     
        LOCAL sMyStr AS STRING
     
        SELECT CASE CBMSG
     
            CASE %WM_COMMAND
     
                SELECT CASE CBWPARAM
     
                    CASE %CANCEL
     
                        DIALOG END CBHNDL
     
                    CASE %LOWER
                        CONTROL GET TEXT hDlg, %LABEL1 TO sMyStr
                        Lower sMyStr
                        CONTROL SET TEXT hDlg, %LABEL1, sMyStr
     
                END SELECT
        END SELECT
     
    END FUNCTION
    
    '==============================================================================
    SUB Lower(zStr AS STRING)
     
        DIM s AS STRING PTR
        DIM i AS INTEGER
     
        s = VARPTR(zStr)
         
        FOR i = 1 TO LEN(zStr)
            IF @s = "A" THEN @s = "a"
            INCR s
        NEXT
     
    END SUB

  • #2
    Use VARPTR() only on fixed length strings and ASCIIZ strings Use STRPTR() on dynamic strings. (To point to the string data).

    (zStr As String) looks like a dynamic string to me, so use STRPTR() to find the location of the data.

    Tim



    ------------------

    Comment


    • #3
      Lasse --
      You incorrect understand pointers.
      For example, this works

      Code:
      Sub Lower(zStr As String)
      
          Dim s As Byte Ptr
          Dim i As Integer
      
          s = StrPtr(zStr)
          For i = 1 To Len(zStr)
             If (@s >= 65) And (@S <= 90) Then @s = @s + 32
              Incr s
          Next
      
      End Sub
      but in your variant @s means whole string line.

      Varptr(zStr) means address with information about string (address, length - not described).
      Incr s ???
      After first Incr s: @s = ... you will receive GPF.

      ------------------


      [This message has been edited by Semen Matusovski (edited February 27, 2000).]

      Comment


      • #4
        Tim,

        I tried STRPTR and it points directly to a place which GPFs immediately?

        Semen,

        that makes it work OK and I understand why. (From PB/DLL help: Each string variable uses four bytes which contain a handle number that is used internally to locate information about a string.)

        The sample I included from the Help-file has an error then:

        Let's say that we want to scan all the characters in a buffer, replacing all upper case "A"s with lower case "a"s. The code might look something like this:
        followed by the sub Lower I included in my earlier post. It is not only an typographic error (DIM s AS STRING PTR vs. DIM s AS BYTE PTR) because the sample lets you understand that a variable type STRING PTR is already pointing to the first character. It says do INCR s to access individual characters.

        What about fixed length string and ASCIIZ strings then?

        PB/DLL help says
        Also, unlike variable-length strings, fixed-length strings don't use handles. When you pass a fixed-length string to a routine, you are actually passing a pointer to the string’s data.
        Also, unlike dynamic strings, ASCIIZ strings do not use handles. When you pass an ASCIIZ string to a routine, you are actually passing a pointer to the string’s data.
        How is that supposed to be understood in relation to getting pointer to the first character in a string having this type?

        As far as I can tell now, they must be treated like variable strings. Am I wrong again?

        Lasse Rantanen
        [email protected]

        Comment


        • #5
          Lasse --
          There is no StrPtr for ASCIIZ and fixed-length string variables.
          (try this by youself - compiler is unhappy).
          VarPtr for them return the beginning of string information similar StrPtr for variable-length strings (interesting).
          To say true, I prefer first two types for such operations, because all is clear with their interiours.

          PS. I can't find a place about you wrote in first message (which topic ?)




          ------------------

          Comment


          • #6
            Semen,

            sure - VARPTR not STRPTR - but otherwise similar. For example

            SUB Lower(zStr AS ASCIIZ)

            DIM s AS BYTE PTR

            s = VARPTR(zStr)

            That help file reference is to Users Guide -> Data Types -> Pointer Data Type, 13th paragraph there (depending how you calculate those paragraphs).

            Lasse Rantanen
            [email protected]



            ------------------

            Comment


            • #7
              Hmmm ... I see.
              But what authors wanted to say, it's question to Lance or Dave.
              Difficult to imagine that this is part of living program.

              ------------------

              Comment


              • #8
                Hello,

                I have not used pointers at all in PB yet, but I’m about to dive into them. I read this post and I think the problem here is the help file documentation. Like I said I don’t know for sure, but the following examples might be wrong in the help file, or I’m way out to lunch.

                ==================================================
                DIM y AS STRING PTR
                DIM z AS STRING PTR
                DIM TmpStr AS STRING
                y = VARPTR(TmpStr) ' y points to TmpStr
                z = VARPTR(y) ' z points to y
                @y = "A" ' put an "A" in TmpStr
                @@z = "B" ' overwrite it with a "B"
                Display @y ' display the target value of y

                ~In this example, I believe that the line y = VARPTR(TmpStr) should use STRPTR instead.

                ===================================================

                “Declare Function GetSum! Lib "SUMS.DLL" (Prices!, ByVal Elements%)
                By not using the ByVal keyword before the variable Prices!, we've told Visual Basic to pass a memory address to the variable.”

                ~Then it says do this:
                “DIM PriceData AS SINGLE PTR”
                “PriceData = VARPTR(Price!)”

                ~If the VB passes the memory address for the variable Prices!, why do we take this address and convert it using VARPTR? Or does PB just assign this address to the variable Prices! first and then we convert it back using VARPTR?

                =====================================================

                “DIM DataPtr AS INTEGER PTR
                DIM z%(0 to 8, 0 to 3)
                DataPtr = VARPTR(z%(1, 1))
                FOR y = 0 TO 3
                FOR x = 0 TO 8
                Value% = @DataPtr[x OF 8, y OF 3]
                NEXT x
                NEXT y”

                ~should the line DataPtr = VARPTR(z%(1,1)) be: z%(0,0) ??? If the array is dim’d 0-8 and 0-3 don’t we want the address of 0-0???

                ======================================================

                Like I said, I could be wrong about all this, but this was confusing to me.

                Thanks,
                Colin Schmidt

                ------------------
                Colin Schmidt & James Duffy, Praxis Enterprises, Canada

                Comment


                • #9
                  Disclaimer: I'm typing this off the top of my head away from all
                  reference material...

                  VARPTR of a dynamic string points to the string's handle. For example:
                  Code:
                  DIM a$
                  DIM z as STRING PTR
                  a$ = "123"
                  z = VARPTR(a$)
                  ' Now we can use a$ and @z interchangably:
                  MSGBOX a$ & $CRLF & @z
                  MSGBOX MID$(@z,1,2) ' produces "12"
                  STRPTR of a dynamic string points to the string's actual data,
                  provided the string is non-null (ie, it contains actual data).
                  Code:
                  DIM a$, b$
                  dim z as BYTE PTR, x&
                  a$ = "1234567890"
                  z = STRPTR(a$)
                  FOR x& = 0 to len(a$)
                    b$ = b$ + CHR$(@z[x])
                  NEXT x&
                  MSGBOX b$ & $CRLF & b$
                  As pointed out elsewhere in this thread, STRPTR() cannot be used
                  with ASCIIZ and fixed-length strings. VARPTR() in these cases
                  points directly to the data stored in these strings. These
                  classes of string occupy a fixed memory location at runtime so
                  the address is valid regardless of the contents of the string.

                  These different classes of pointer can be very flexible.
                  For example, take the case where a dynamic string contains a
                  given amount of data with intersperced NULL bytes. By assigning
                  the STRPTR of an dynamic string (which is internally terminated
                  with an invisible NULL byte) to an ASCIIZ pointer, we can parse
                  the sections of the dynamic string as if it were a bunch of
                  ASCIIZ strings stored in consecutive order. While PARSE$() can
                  also be used in this case, it is a good example of how to
                  manipulate data at the byte level.


                  ------------------
                  Lance
                  PowerBASIC Support
                  mailto:[email protected][email protected]</A>
                  Lance
                  mailto:[email protected]

                  Comment


                  • #10
                    I forgot one important point: STRING PTR is not the same as STRPTR().


                    ------------------
                    Lance
                    PowerBASIC Support
                    mailto:[email protected][email protected]</A>
                    Lance
                    mailto:[email protected]

                    Comment


                    • #11
                      Lance,

                      this sample in help file is misleading.

                      SUB Lower(zStr AS STRING)
                      DIM s AS STRING PTR
                      DIM i AS INTEGER

                      s = VARPTR(zStr)
                      FOR i = 1 TO LEN(zStr)
                      IF @s = "A" THEN @s = "a"
                      INCR s
                      NEXT
                      END SUB

                      I got wrong idea about this pointer based on this sample. It gives you the impression that string pointer can be used to point individual characters in a string, which is not true.

                      I think the main issue which makes this matter somewhat confusing is that the help file does not say that, given e.g.
                      Code:
                         DIM s AS STRING PTR
                      
                         s = STRPTR(string)
                      then @s points to the whole string. In order to access individual characters, you need a pointer type BYTE PTR which can then be used to point to individual characters as Semen pointed out to me.

                      Lasse Rantanen
                      [email protected]

                      ------------------

                      Comment


                      • #12
                        Ouch! I'll post an errata about this one... thanks.


                        ------------------
                        Lance
                        PowerBASIC Support
                        mailto:[email protected][email protected]</A>
                        Lance
                        mailto:[email protected]

                        Comment

                        Working...
                        X