April 27, 2024, 04:25:42 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Dynamic Variables and Indirection (And a possible answer to Barry's question)

Started by Jim Scott, January 05, 2007, 07:09:32 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Jim Scott

In looking at ways to help answer Barry's question in the "Possible problem with strings or is it me?" thread I came up with another question myself.  I thought one way to make best use of memory was to use the new command and get and set data using indirection with pointers.  And then when finished with the structure, the delete command would free up the memory.

In the following code I can only get to the first character of each of three lines.  Any hints on how to Print the rest of the strings using this method?

Def pS As Pointer

pS = New(String, 4000)

OpenConsole
*<String> pS[0] = "This is the first line of text"
*<String> pS[1] = "And this is the second line of text"
*<String> pS[3999]= "But this is the last line of text"
Print *pS[0]
Print *pS[1]
Print *pS[3999]
Print

delete pS

Print "Press any key to exit"
Do:Until INKEY$ <> ""
CloseConsole
END


Which puts the following to the console

T
A
B

Press any key to exit
Jim Scott

Ionic Wind Support Team

I've explained this somewhere before ;)

NEW just returns a pointer to allocated memory, it really doesn't care what type you specify as it is just using the type to calculate the size of the memory allocated.  So the memory isn't type aware. 

A string array is actually a two dimension array, and not a single index like you are specifying.  So you have to tell the compiler two indexes, the string and the character index like so:


Def pS As Pointer

pS = New(String, 4000)

OpenConsole
*<String> pS[0,0] = "This is the first line of text"
*<String> pS[1,0] = "And this is the second line of text"
*<String> pS[3999,0]= "But this is the last line of text"
Print *pS[0,0]
Print *pS[1,0]
Print *pS[3999,0]
Print

delete pS

Print "Press any key to exit"
Do:Until INKEY$ <> ""
CloseConsole
END


You're not really gaining any benefits though.  Your array still uses the entire 1MB when allocated.  Barry was asking if a string was only as large as its contents and the answer was no.

Paul.
Ionic Wind Support Team

Jim Scott

ok, I get that a collection of vectors (Strings in this case) is a two dimensional array of sorts.  But what I don't get in your example below is that it doesn't seem to matter what value is in the second parameter.  For instance;

Print *pS[0,0]

Puts out the same string as;

Print *pS[0,5000]

I would think that with this syntax;

Print *pS[0,5]

Would print the line

"is the first line of text"

What am I missing here?
Jim Scott

Ionic Wind Support Team

Call it an idiosynchracy.  The compiler expects the second index, but doesn't use it for anything.  Because there really isn't an array defined, you're just typecasting memory to a string.  Which is why I mentioned that NEW doesn't know anything about the type of a variable except for its size. 

Internally the calculation works because the compiler knows a STRING type is 255 characters and the formula for accessing array indexes is:

address = base + (index2 * dim1 + index1) * datasize

Since there isn't an array variable the dim1 value ends up to be zero so the formula ends up looking like this:

address = base + (index2 * 0 + index1) * 255

Now before you ask why it doesn't work with a single index I will attempt to answer that.  One of the features of Emergence is the ability to work with single characters in a string without having to use Left$, Mid$ and the like.  So if a string variable doesn't have any dimensions and you use the array [  ] symbol with a single index then the value returned/set is a single character.  Internally there is a structure (UDT) the compiler uses for variables when they are defined and the arrays dimensions are stored in that structure.  In EBASIC terms, much simplified, it might look like this:

TYPE variable
  ISTRING name[64]
  INT size
  INT type
  INT bArray
  INT dim[3]
ENDTYPE

When the parser encounters something like DEF a[10] as STRING that structure is filled in like so:

var.name = "a"
var.type = TYPE_STRING
var.array = TRUE
var.dim[0] = 10
var.size = 2550

So when you use a single index it can tell whether to return a single character or a string from an array.

print a[0]
...
var = get_variable("a")
if(var.array)
...'get the string at the index specified
else
...'get the character at the index specified.

Now back to the other subject.  When you created the pointer with NEW it is just memory without a real type and the variable is a pointer type with no array dimensions, bArray is FALSE.

'allocate 255 * 4000 bytes of memory
pS = NEW(String, 4000)

'access that memory
Print *pS[0]

'pS' is the variable the compiler looks at to see if it is an array.  Since the test returns FALSE and it is typecast to a string the compiler returned/set the character at that index.

Hope that helps in your understanding.

Paul.

Ionic Wind Support Team

Jim Scott

Thanks, yes that does help my understanding.  To help me a little more, I have another related question.

Let's say we have the following code;

Def s[10] As String
Def a As String
s[0] = "This is a string"
s[2] = "Another silly love song"
a = s[2]


I know that I can get to any one character in "s" by assigning the entire line to another string, say "a", then getting a[n].  Is there a way of using "s" as a 10 x 255 array and addressing a single character directly with something like s[x,y] ?   Also, is there a way of getting more than one character at time.  For instance, can I pull "silly" out of s[2] above directly using some kind of range?  Or do I just have to use a loop and get one charater at a time?

Jim
Jim Scott

Ionic Wind Support Team

When your using an actual array you have to use BASIC commands ;)

'get the 1th character of string 2
c = MID$ s[1],11,1

'extract a string three characters long from string 3
c = MID$ s[2], 1, 3



Ionic Wind Support Team

Jim Scott

Got me!  I was thinking of arrays in general and using the strings as an example.  So, I didn't even think of using the BASIC $tring commands.  What if I have an array of doubles and I want to get a subset withing the array?  I guess there isn't a way of doing this without loops etc.  I guess this gets into a discussion of whether to include matrix operators etc....
Jim Scott

Ionic Wind Support Team

An array of doubles is different since you would be directly creating the two dimension array and accessing whatever element you wanted.  There is no character/string switch like there is with string arrays.

If you really wanted to copy say 10 double values from one array to another without using a loop you could use the API function RtlMoveMemory and pointers to the arrays.  Of course it really is no different from using a loop since that is what RtlMoveMemory does internally anyway.

Paul.

Ionic Wind Support Team

Jim Scott

I'll stick with Matlab for doing any matrix math I need.  Part of my problem with BASIC is my background with Matlab.  I sometimes forget that Matlab cost me $5,500 back in 1998 (I still run R12) and EBasic cost me a total of $35.00 in the year 2006.  Different tool for a different job.  Thanks again.
Jim Scott

barry

I think the reason you're having to explain this so much is that the help doesn't explain much.  I looked for the answer to my question in the help before asking it.  My initial question to myself was whether:

STRING s[10]

allocated 10 strings or a string of length 10.  I didn't find that in the help so I played around with it and figured it out and it was during that playing that I came up with the question I asked here.

I think that section of the help could use more explanation of just what a string and an array of strings is and how (and when) they're constructed in memory and how they're specified.

Barry