Help! Anxiety over Arrays!

New to FreeBASIC? Post your questions here.
VeebDeeb
Posts: 3
Joined: Sep 02, 2007 11:23
Location: Philadelphia, PA, USA

Help! Anxiety over Arrays!

Postby VeebDeeb » Sep 09, 2007 4:16

I'm new to FreeBASIC -- a refugee from Visual Basic who thought that ten years of development experience was all for nought. Then I found the speed "shoot outs". BASIC was still alive, and FreeBASIC was faster than anything short of C.

So I have spent the past week happily diving in.

However, there are a lot of "quirks" in FreeBASIC -- they are not necessarily bugs, but several things don't work the way they did in QB and VB. I expected that, but I've hit a couple of dead ends.

The biggest pitfall for me has been arrays. I am re-writing a lot of my VB language-study software into FB, and most of it depends on using arrays to process lists of words -- sometimes hundreds of thousands of words. Arrays are vital to jobs like these.

I haven't been able to pass arrays through Functions.

Subs seem to tolerate passing arrays. But most of my code is function-oriented!

Here is what DOES NOT work:

Code: Select all

Declare Function ShuffleArray(InAry() As String) As String()
Declare Function Join(InArry() As String, Delim As String) As String

Randomize Timer

Function ShuffleArray(InAry() As String) As String()
   Dim i As Integer
   Dim AryCount As Integer
   Dim As Integer j1, j2

   AryCount = UBound(InAry) + 1

   For i = 1 To AryCount * Sqr(AryCount)
      j1 = Int(AryCount * Rnd())
      j2 = Int(AryCount * Rnd())
      Swap InAry(j1), InAry(j2)
   Next
   
   Return InAry
      
End Function

' === Dependent function =======

Function Join(InArry() As String, Delim As String) As String
   Dim i As Integer
   Dim OutTxt As String
   Dim AryLen As Integer
   Dim DelimLen As Integer
   Dim ThisLen As Integer
   Dim ThisTxt As String
   Dim OutTxtLen As Integer
   Dim OutTxtPoj As Integer = 1
   
   AryLen = UBound(InArry)
   DelimLen = Len(Delim)

   ' Get total len of strings
   For i = 0 To AryLen
      OutTxtLen = OutTxtLen + Len(InArry(i)) + DelimLen 
   Next
   
   ' Allocate string space
   OutTxt = String(OutTxtLen - DelimLen, "~")
      
   ' Assemble string using _ Mid() _ -- it's faster than _ String & String _
   For i = 0 To AryLen
      If i = AryLen Then
         Delim = ""
      End If
      ThisTxt = InArry(i) & Delim
      ThisLen = Len(ThisTxt)
      Mid(OutTxt, OutTxtPoj, ThisLen) = ThisTxt
      OutTxtPoj = OutTxtPoj + ThisLen
   Next
   
   Return OutTxt
   
End Function

/' =================================
   Trial Runs -- no can do
   ================================= '/

Dim Ary(4) As String
Ary(0) = "Atropos"
Ary(1) = "Klotho"
Ary(2) = "Lachesis"
Ary(3) = "Terpsichore"
Ary(4) = "Zippy"

Dim NewAry(4) As String

Dim a As Integer

For a = 1 To 20
   Randomize Timer
   NewAry = ShuffleArray(Ary())
   ? Join(NewAry(), ", ")
   ? ""
Next

Sleep

Here is what DOES work:

Code: Select all

Declare Sub ShuffleArray(InAry() As String)
Declare Function Join(InArry() As String, Delim As String) As String

Randomize Timer

Sub ShuffleArray(InAry() As String)
   Dim i As Integer
   Dim AryCount As Integer
   Dim As Integer j1, j2

   AryCount = UBound(InAry) + 1

   For i = 1 To AryCount * Sqr(AryCount)
      j1 = Int(AryCount * Rnd())
      j2 = Int(AryCount * Rnd())
      Swap InAry(j1), InAry(j2)
   Next
      
End Sub

' === Dependent function =======

Function Join(InArry() As String, Delim As String) As String
   Dim i As Integer
   Dim OutTxt As String
   Dim AryLen As Integer
   Dim DelimLen As Integer
   Dim ThisLen As Integer
   Dim ThisTxt As String
   Dim OutTxtLen As Integer
   Dim OutTxtPoj As Integer = 1
   
   AryLen = UBound(InArry)
   DelimLen = Len(Delim)

   ' Get total len of strings
   For i = 0 To AryLen
      OutTxtLen = OutTxtLen + Len(InArry(i)) + DelimLen 
   Next
   
   ' Allocate string space
   OutTxt = String(OutTxtLen - DelimLen, "~")
      
   ' Assemble string using _ Mid() _ -- it's faster than _ String & String _
   For i = 0 To AryLen
      If i = AryLen Then
         Delim = ""
      End If
      ThisTxt = InArry(i) & Delim
      ThisLen = Len(ThisTxt)
      Mid(OutTxt, OutTxtPoj, ThisLen) = ThisTxt
      OutTxtPoj = OutTxtPoj + ThisLen
   Next
   
   Return OutTxt
   
End Function

/' =================================
   Trial Runs -- this one works fine
   ================================= '/

Dim Ary(4) As String
Ary(0) = "Atropos"
Ary(1) = "Klotho"
Ary(2) = "Lachesis"
Ary(3) = "Terpsichore"
Ary(4) = "Zippy"

Dim a As Integer

For a = 1 To 20
   Randomize Timer
   ShuffleArray(Ary())
   ? Join(Ary(), ", ")
   ? ""
Next

Sleep


Re-writing one function block is not a big deal, but I have hundreds of function blocks to analyze, categorize, inflect, tag, stem, and otherwise process words in about eight languages. Besides which, I find it easier to think in terms of how functions work.

Arrays have thrown me for a loop. I'm sure I must have made some knuckle-headed mistake that I can't see. Can anyone provide a brief tutorial about how to pass arrays in FB?

Thanks in advance!

:vbdb:

PS -- Next hurdle: Pointers
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Postby anonymous1337 » Sep 09, 2007 4:39

Yes. You can pass arrays, but you can't return them D:
stylin
Posts: 1253
Joined: Nov 06, 2005 5:19

Postby stylin » Sep 09, 2007 5:14

VeebDeeb, array returns may be supported in the future, but for now you can simply pass in the result array, if you need to preserve the original:

declare sub ShuffleArray(array() as string, result() as string)

Fixed-length arrays can be members of user-defined types (UDTs), which can be returned by procedures. But since procedures always return by value, you'll have lots of array copying going on. Better to pass the result array, use pointers or wait for array returns.
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Sep 10, 2007 22:01

You could pass your array like this....

Code: Select all

#Define MAX_INDEX 10
Dim MyArray(MAX_INDEX) As Integer

Sub ChangeArray (pArray As Integer Ptr)
   
   pArray[1] = 1300
   pArray[5] = 2200
   
End Sub

'START

   MyArray(1) = 100
   MyArray(5) = 200
   
   Print "Index 1=" & MyArray(1)
   Print "Index 5=" & MyArray(5)
   
   
   ChangeArray (@MyArray(0)) 'Pass pointer to beginning of array
   
   Print "Index 1=" & MyArray(1)
   Print "Index 5=" & MyArray(5)

   Sleep
   
End



Cheers!
-Vince
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Postby anonymous1337 » Sep 10, 2007 22:53

vdecampo, yes but then he will also have to pass the size of his array :D
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Sep 10, 2007 22:58

anonymous1337 wrote:vdecampo, yes but then he will also have to pass the size of his array :D


No, he already knows the size...

#Define Max_Index 10

:-o
notthecheatr
Posts: 1759
Joined: May 23, 2007 21:52
Location: Cut Bank, MT
Contact:

Postby notthecheatr » Sep 10, 2007 23:46

Or he could create a strucure with the array itself plus the size, then pass the structure... I usually do something like that.
jcfuller
Posts: 324
Joined: Sep 03, 2007 18:40

Postby jcfuller » Sep 11, 2007 20:44

I too was surprised when I discovered no array passing to procedures.
PowerBASIC has spoiled me.
Firstly I want to say I am very impressed with FreeBasic. I've been away
from programming for a few years and just discovered fb a couple weeks ago.
Keep up the Great work.

Anyway I process a lot of Tab delimited text files and this is what I came up with to handle my demands. Seems to work

James





Code: Select all

FUNCTION _
  ParseOne ( _
    S1          AS STRING,_
    Dlim        AS STRING,_
    S2          AS STRING _
  ) AS INTEGER

  DIM bPtr      AS UBYTE PTR,_
      sLoc      AS LONG,_
      DlimVal   AS UBYTE, _
      Index     AS LONG, _
      LenOfStr  AS LONG

  DIM AS UINTEGER PTR uiPtr


  DIM AS UINTEGER ui
  S2 = SPACE(LEN(S1))
  uiPtr = STRPTR(S2)

   
  DIM AS INTEGER sLen,DelimF

     
  DlimVal = ASC(Dlim)
  bPtr = STRPTR(S1)
  LenOfStr = LEN(S1)
  Index = 1
  ui = 1
  DO
    IF sLoc > LenOfStr THEN       
      uiPtr[Index] = (ui SHL 16) + sLen-1
      EXIT DO
    END IF 
   
    IF bPtr[sLoc] = DlimVal THEN
        DelimF=1
        uiPtr[Index] = (ui SHL 16) + sLen
        sLen = 1
        Index+=1
        sLoc+=1
    ELSE
       IF DelimF THEN       
         ui = sLoc
         DelimF = 0       
       END IF 
      sLen+=1 
    END IF
    sLoc+=1   
  LOOP     
 
  FUNCTION = Index
END FUNCTION

'============================================================================== 
#DEFINE TEST
#IFDEF TEST
DIM AS STRING S3,S2
DIM AS INTEGER i,j,k
DIM S1() AS STRING
DIM AS UINTEGER PTR uiPtr       
DIM AS USHORT  Start,wLen
S3 = "This"+CHR(9)+" is"+CHR(9)+" a line of"+CHR(9)+" Text with \n" +CHR(9)+"Another Line"

i = ParseOne(S3,CHR(9),S2)
PRINT "i = ";STR(i)
uiPtr = STRPTR(S2)

IF i THEN         
  REDIM S1(1 TO i)
  FOR j = 1 TO i
    Start = HIWORD(uiPtr[j])
    wLen =  LOWORD(uiPtr[j])         
    S1(j) = MID$(S3,Start,wLen)
    PRINT S1(j)
  NEXT j
END IF
PRINT "OK"   




SLEEP
#ENDIF

v1ctor
Site Admin
Posts: 3799
Joined: May 27, 2005 8:08
Location: SP / Bra[s]il
Contact:

Postby v1ctor » Sep 12, 2007 3:31

You can pass arrays as parameter since version v0.1 (the compiler itself uses that feature). What can't be done yet is to return arrays from functions as results (neither PB supports that, if i remember it doesn't even support to return UDTs from functions).
jcfuller
Posts: 324
Joined: Sep 03, 2007 18:40

Postby jcfuller » Sep 12, 2007 10:05

v1ctor wrote:You can pass arrays as parameter since version v0.1 (the compiler itself uses that feature). What can't be done yet is to return arrays from functions as results (neither PB supports that, if i remember it doesn't even support to return UDTs from functions).


I guess I worded it wrong. I know you can pass IN but cannot alter with the results reflected outside the procedure.

I don't want this to get into PB - FreeBasic comparison but you need to get your facts straight.

PB cannot RETURN as in FUNTION = UDT but iit can Change/Redim an array.

James


PBCC 4.03 code

Code: Select all

#COMPILE EXE
#DIM ALL

TYPE Type1
    One AS LONG
    Two AS STRING * 10
    Three AS LONG
END TYPE

FUNCTION TestArray(S1() AS STRING, MyUdt AS Type1)AS LONG
  DIM i AS LONG
  REDIM S1(9)
  FOR i = 0 TO 9
      S1(i) = "Number "+STR$(i)
      MID$(MyUdt.Two,i+1,1)=FORMAT$(i)
   NEXT i
   FUNCTION = 123
END FUNCTION

FUNCTION PBMAIN () AS LONG
  DIM i AS LONG
  DIM j AS LONG
  DIM Udt1 AS Type1
  DIM S1(1) AS STRING
  j = TestArray(S1(),Udt1)
  FOR i = 0 TO 9
      PRINT S1(i),MID$(Udt1.Two,i+1,1)
  NEXT i
 
    WAITKEY$

END FUNCTION

Sisophon2001
Posts: 1704
Joined: May 27, 2005 6:34
Location: Cambodia, Thailand, Lao, Ireland etc.
Contact:

Postby Sisophon2001 » Sep 12, 2007 11:07

jcfuller wrote:<snip>
I guess I worded it wrong. I know you can pass IN but cannot alter with the results reflected outside the procedure.
<snip>


I am sure that you can alter an array inside a function and have the results reflected outside. Perhaps I am misunderstanding something. Your PB code looks like it works perfectly in FB (with appropriate changes), but I don't have PB so I might be missing something.

I will try using FirstBASIC which I think I have someplace.

Garvan

EDIT: Could not figure out how to get it to run in FirstBASIC, but this is what I get running the code in FB on Linux.
garvan@suse:~/programming/fb> ./t
Number 0 0
Number 1 1
Number 2 2
Number 3 3
Number 4 4
Number 5 5
Number 6 6
Number 7 7
Number 8 8
Number 9 9
garvan@suse:~/programming/fb>


Garvan
jcfuller
Posts: 324
Joined: Sep 03, 2007 18:40

Postby jcfuller » Sep 12, 2007 12:14

Sisophon2001:
This should be the output:

Code: Select all

Number  0     0
Number  1     1
Number  2     2
Number  3     3
Number  4     4
Number  5     5
Number  6     6
Number  7     7
Number  8     8
Number  9     9


Here is the FreeBasic code that compiles on XP but goes off into lala land when run.

Code: Select all

TYPE Type1
    One AS LONG
    Two AS STRING * 10
    Three AS LONG
END TYPE

FUNCTION TestArray(S1() AS STRING, MyUdt AS Type1)AS LONG
  DIM i AS LONG
  REDIM S1(9)
  FOR i = 0 TO 9
      S1(i) = "Number "+STR(i)
      MID(MyUdt.Two,i+1,1)=STR(i)
   NEXT i
   FUNCTION = 123
END FUNCTION

FUNCTION PBMAIN () AS LONG
  DIM i AS LONG
  DIM j AS LONG
  DIM Udt1 AS Type1
  DIM S1(1) AS STRING
  j = TestArray(S1(),Udt1)
  FOR i = 0 TO 9
      PRINT S1(i),MID$(Udt1.Two,i+1,1)
  NEXT i

    SLEEP

END FUNCTION
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Postby MichaelW » Sep 12, 2007 12:20

Your PB code, as well as your FB version, is re-dimensioning a static array. If you change it to a dynamic array, by any of at least three different methods, remove the PB-specific components, and add the header file necessary to use FORMAT, then it compiles and works OK. The failure to catch the error, even when compiling with -exx, is a bug IMO.

Code: Select all

'#COMPILE EXE
'#DIM ALL

#include "vbcompat.bi"

Type Type1
    One As Long
    Two As String * 10
    Three As Long
End Type

Function TestArray(S1() As String, MyUdt As Type1)As Long
  Dim i As Long
  Redim S1(9)
  For i = 0 To 9
      S1(i) = "Number "+Str$(i)
      Mid$(MyUdt.Two,i+1,1)=FORMAT$(i)
   Next i
   Function = 123
End Function

Function PBMAIN () As Long
  Dim i As Long
  Dim j As Long
  Dim Udt1 As Type1
  ''Dim S1(1) As String  '<=== creates a static array
  redim S1(1) As String  '<=== creates a dynamic array
  j = TestArray(S1(),Udt1)
  For i = 0 To 9
      Print S1(i),Mid$(Udt1.Two,i+1,1)
  Next i

  'WAITKEY$
  return 1

End Function

print PBMAIN()
sleep

Code: Select all

Number 0      0
Number 1      1
Number 2      2
Number 3      3
Number 4      4
Number 5      5
Number 6      6
Number 7      7
Number 8      8
Number 9      9
 1
jcfuller
Posts: 324
Joined: Sep 03, 2007 18:40

Postby jcfuller » Sep 12, 2007 13:20

Excellent MichaelW.
Just a red faced FreeBasic noob here:)

Thank You

James
v1ctor
Site Admin
Posts: 3799
Joined: May 27, 2005 8:08
Location: SP / Bra[s]il
Contact:

Postby v1ctor » Sep 13, 2007 3:38

What i meant was something like this:

Code: Select all

'' not supported by FB or PB
function retarray as integer()
  dim array() as integer
  return array()
end function
somearray() = retarray


Code: Select all

'' supported by FB and not by PB (AFAIK)
type foo
 i as integer
 j as integer
end type
function retudt as foo
 return type(1, 2)
end function
dim f as foo = retudt

Return to “Beginners”

Who is online

Users browsing this forum: Majestic-12 [Bot] and 6 guests