Page 1 of 1

Issue with loading/saving an array of structures

Posted: Tue Nov 23, 2021 12:31 pm
by XCoder
I created an array with the following structure:

Code: Select all

Structure SQUAREDATA
  SquareNumber.i
  Array InnerSquare.i(8)
  ReadOnly.b
EndStructure

Dim squareData.SQUAREDATA(82)
I run the following program to set up the array with test data and save it to disk:

Code: Select all

Structure SQUAREDATA
  SquareNumber.i
  Array InnerSquare.i(8)
  ReadOnly.b
EndStructure

Dim squareData.SQUAREDATA(82) ;Array range is 0-81

#FileHandle = 0
#SizeOfDataStructure = SizeOf(SQUAREDATA) * 82

Procedure InsertData(Array squareData.SQUAREDATA(1))
For j = 0 To 81
  For k = 0 To 7
    squareData(j)\InnerSquare(k) = j*k
  Next
Next
EndProcedure

Procedure SaveSquareData(Array squareData.SQUAREDATA(1))
  FileNamePath$ = SaveFileRequester("Save test file", "", "Test file *.tst|*.tst", 0)
  Extension$ = GetExtensionPart(FileNamePath$)
  If Extension$ = "" And FileNamePath$<>""
    FileNamePath$ = FileNamePath$ +".tst"
  EndIf
  If FileNamePath$<>""
    If CreateFile(#FileHandle, FileNamePath$)
      WriteData(#FileHandle, @squareData(), #SizeOfDataStructure)
      CloseFile(#FileHandle)
    Else
      MessageRequester("WARNING", "Cannot create this file", #PB_MessageRequester_Warning)
    EndIf
  EndIf
EndProcedure

InsertData(squareData())
SaveSquareData(squareData())

For j = 0 To 81 ;Check the contents of the array
  For k = 0 To 7
    Debug squareData(j)\InnerSquare(k)
  Next
Next
But when I try to load the code with the following program and view the data, I get the error message "Array index out of bounds" when the debug part of the code runs.

Code: Select all

Structure SQUAREDATA
  SquareNumber.i
  Array InnerSquare.i(8)
  ReadOnly.b
EndStructure

Dim squareData.SQUAREDATA(82) ;Array range is 0-81

#FileHandle = 0
#SizeOfDataStructure = SizeOf(SQUAREDATA) * 82

Procedure LoadSquareData(Array squareData.SQUAREDATA(1))
    FileNamePath$ = OpenFileRequester("Open test file", "", "Test file *.tst|*.tst", 0)
    If FileNamePath$<>""
      If OpenFile(#FileHandle,FileNamePath$)
        ReadData(#FileHandle,@squareData(), #SizeOfDataStructure)
        CloseFile(#FileHandle)
        result=#True
      EndIf
    EndIf
  ProcedureReturn result
EndProcedure

LoadSquareData(squareData())

For j = 0 To 81
  For k = 0 To 7
    Debug squareData(j)\InnerSquare(k)
  Next
Next
Can anybody tell me why this happens and how to resolve the issue?

I am using Windows 10 (64k).

Re: Issue with loading/saving an array of structures

Posted: Tue Nov 23, 2021 1:57 pm
by spikey
"What you get is not actually what you think you're getting" (wyginawytyg never caught on though) ;-)

When you put a dynamically sizeable array into a structure - what actually gets put into the structure is a pointer to the child array. The child array will get its own memory allocation (probably nearby but not sequentially). The compiler knows this though and automatically dereferences the pointers appropriately when a structured object is accessed.

WriteData and ReadData are purely block based and don't understand dereferencing at all. The read back program corrupts the receiving array's pointers with out of date information from the writing program. A failure ensues when the subsequent routine attempts to dereference properly because the layout is now wrong.

What you do about this depends what you are trying to achieve. If your child arrays are always going to be 8 integers then you could use
a static array instead. This does get laid out sequentially and should round trip properly - see below. (Note the revised syntax using [] - your read back program will need to follow suit).

If you need dynamically sized arrays then you could:
  • Roll your own read and write routines and embed the output data with some appropriate sizing data so you can recover the data correctly when you read it back. You'll need to take complete charge of the process though.
  • Use the JSON library which provides some functions to do this sort of thing, if you don't mind your save data becoming JSON.
  • Use the XML library, ditto.

Code: Select all

Structure SQUAREDATA
  SquareNumber.i
  InnerSquare.i[8]
  ReadOnly.b
EndStructure

Dim squareData.SQUAREDATA(82) ;Array range is 0-81

#FileHandle = 0
#SizeOfDataStructure = SizeOf(SQUAREDATA) * 82

Procedure InsertData(Array squareData.SQUAREDATA(1))
For j = 0 To 81
  For k = 0 To 7
    squareData(j)\InnerSquare[k] = j*k
  Next
Next
EndProcedure

Procedure SaveSquareData(Array squareData.SQUAREDATA(1))
  FileNamePath$ = SaveFileRequester("Save test file", "", "Test file *.tst|*.tst", 0)
  Extension$ = GetExtensionPart(FileNamePath$)
  If Extension$ = "" And FileNamePath$<>""
    FileNamePath$ = FileNamePath$ +".tst"
  EndIf
  If FileNamePath$<>""
    If CreateFile(#FileHandle, FileNamePath$)
      WriteData(#FileHandle, @squareData(), #SizeOfDataStructure)
      CloseFile(#FileHandle)
    Else
      MessageRequester("WARNING", "Cannot create this file", #PB_MessageRequester_Warning)
    EndIf
  EndIf
EndProcedure

InsertData(squareData())
SaveSquareData(squareData())

For j = 0 To 81 ;Check the contents of the array
  For k = 0 To 7
    Debug squareData(j)\InnerSquare[k]
  Next
Next

Re: Issue with loading/saving an array of structures

Posted: Tue Nov 23, 2021 2:37 pm
by XCoder
@spikey: Thanks for your reply. I overlooked the issue of using dynamic arrays - I spent ages trying to resolve this issue. Using a static array will resolve my issue.

Re: Issue with loading/saving an array of structures

Posted: Tue Nov 23, 2021 3:41 pm
by mk-soft
I like xml for program data and project data

Link: viewtopic.php?f=12&t=74233

Re: Issue with loading/saving an array of structures

Posted: Wed Nov 24, 2021 3:48 pm
by XCoder
Thanks, mk-soft. I will look at the link you provided