getting the true length of a string stored in an array

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
Jbizzel
Dynamite Dan
Posts: 1537
Joined: Mon May 04, 2020 4:34 pm
Location: Hull
Contact:

getting the true length of a string stored in an array

Post by Jbizzel »

OMG who new this was going to even be a thing. I just assumed basic would know the true length of a string. But then I guess why should it!

Or have I missed something? it there a better way than this example code...

Code: Select all

5 PAPER 7: CLS 
10 DIM a$(3,12)
20 FOR x=1 TO 3
30 READ a$(x)
40 NEXT x
100 FOR x=1 TO 3
130 PRINT a$(x);LEN a$(x);" *"
140 NEXT x
145 FOR c=1 TO 3
150 GO SUB 200: NEXT 
c190 STOP 200 REM cut size down
210 FOR x=1 TO 12
220 LET s$=a$(c)
230 PAPER 5: LET s$=s$(x TO x)
240 IF s$=" " THEN PRINT "len is ";x-1: RETURN 250 NEXT x
3000 DATA "one","fives","twenty-two"
User avatar
TMD2003
Rick Dangerous
Posts: 2045
Joined: Fri Apr 10, 2020 9:23 am
Location: Airstrip One
Contact:

Re: getting the true length of a string stored in an array

Post by TMD2003 »

I've known that was "a thing" since 1980-something. I used a similar method to cut out space padding in Corona Capers, but I've since switched to hard-wiring the string lengths inside the array for a very small increase in array size.

So if you know your maximum string length is going to be 12, then instead of this:

DIM a$(3,12)
a$(1)="one"
a$(2)="fives"
a$(3)="twenty-two"

Do this instead, including the length of each string within the string itself:

DIM a$(3,14)
a$(1)="03one"
a$(2)="05fives"
a$(3)="10twenty-two"

...and PRINT a$(n,3 TO 2+VAL a$(n, TO 2)). Or, to shorten it for a slight increase in brain activity, set the two digits to the position of the last character to print:

DIM a$(3,14)
a$(1)="05one"
a$(2)="07fives"
a$(3)="12twenty-two"

...and PRINT a$(n,3 TO VAL a$(n, TO 2)).

I've extended this further if I've ever needed to PRINT an array AT specific positions - DIM a$(3,18) and have the first two characters as the row, the next two as the column, then the length, then the content.

a$(1)="111503one"
PRINT AT VAL a$(n, TO 2),VAL a$(n,3 TO 4);a$(n,7 TO 6+VAL a$(n,5 TO 6))

It makes sense in context.
Spectribution: Dr. Jim's Sinclair computing pages.
Features my own programs, modified type-ins, RZXs, character sets & UDGs, and QL type-ins... so far!
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: getting the true length of a string stored in an array

Post by catmeows »

I believe DIM a$(3,12) creates array of chars 3x12. I mean it really reserves maximum lenght 12 for each index. If you try to asign bigger string to index, the string will be cut silently to match maximum allowed length. If you assign smaller string, it will ber padded by spaces.
So the answer is: length of string is always 12.
Consider this:

Code: Select all

10 DIM a$(3,5)
20 LET a$(1) = "xxxxxxx"
30 LET a$(2) = "yyy"
40 PRINT a$(1);"!"
50 PRINT a$(2);"!"
60 PRINT a$(3);"!"
Proud owner of Didaktik M
User avatar
1024MAK
Bugaboo
Posts: 3123
Joined: Wed Nov 15, 2017 2:52 pm
Location: Sunny Somerset in the U.K. in Europe

Re: getting the true length of a string stored in an array

Post by 1024MAK »

Darn, I was going to suggest working out the length before storing it in the array, and also storing the value in an array (I was thinking of a separate array).

Mark
:!: Standby alert :!:
“There are four lights!”
Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb :dance
Looking forward to summer later in the year.
RST#08
Drutt
Posts: 30
Joined: Sun Jul 24, 2022 6:29 pm

Re: getting the true length of a string stored in an array

Post by RST#08 »

Here's my approach using embedded CODEs instead.

Code: Select all

10 DIM a$(3,14)
20 RESTORE
30 FOR n=1 TO 3
40 READ b$
50 LET x=LEN b$
60 LET a$(n)=CHR$ x+b$
70 NEXT n
100 REM demo
110 PRINT "Length","String"
120 FOR n=1 TO 3
130 LET x=CODE a$(n,1)
140 LET b$=a$(n,2 TO x+1)
150 PRINT x, BRIGHT 1;b$
160 NEXT n
1000 DATA "cat","dog","zebra"
Note that you need to extract the CODE before printing, RESTORE is optional but does mean you can move to different data sets if need be (RESTORE line), and I've only use BRIGHT here to show the 'proper' extraction of only the required characters. This could all be shortened.
User avatar
Jbizzel
Dynamite Dan
Posts: 1537
Joined: Mon May 04, 2020 4:34 pm
Location: Hull
Contact:

Re: getting the true length of a string stored in an array

Post by Jbizzel »

Thanks guys - some great suggestions here. @TMD2003 - thats so simple - great idea!

Although I like the idea that the Spectrum does all the work itself. So I prefer an approach where the spectrum does the calculations this time.

Actually, I'm glad I did because my 10 year old got interested and ended up editing my games data statement on a real 48k speccy and then saved his version of the game to tape. Just like I was doing, 35 years ago when I was his age. Blimey!
EdToo
Manic Miner
Posts: 228
Joined: Thu Nov 03, 2022 4:23 pm

Re: getting the true length of a string stored in an array

Post by EdToo »

Jbizzel wrote: Sun Dec 10, 2023 5:21 pm
Actually, I'm glad I did because my 10 year old got interested and ended up editing my games data statement on a real 48k speccy and then saved his version of the game to tape. Just like I was doing, 35 years ago when I was his age. Blimey!
Good to know you're bringing them up right, instead of time wasting on iPads.
sn3j
Manic Miner
Posts: 501
Joined: Mon Oct 31, 2022 12:29 am
Location: Germany

Re: getting the true length of a string stored in an array

Post by sn3j »

You could just skip defining the array, instead you restore the DATA line matching the index you actually need.

Code: Select all

  10 FOR i=1 TO 3
  20 RESTORE 100+i: READ s$
  30 PRINT AT 10+i,0; BRIGHT 1;s$
  40 NEXT i
 101 DATA "Blue"
 102 DATA "Green"
 103 DATA "Yellow"
It's a tad slower than array access but you get the true length.
POKE 23614,10: STOP      1..0 hold, SS/m/n colors, b/spc toggle
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: getting the true length of a string stored in an array

Post by ParadigmShifter »

That way also saves memory since you don't have to copy anything into the array (so have to define the data either in the listing as well, unless you load the array off tape).

E.g. lookup version of fizzbuzz (and can do default empty strings as well since READ looks for the first DATA statement after the RESTORE).

Image

Originally I tried using arrays for that but came up against a similar issue to one the OP had.

If you want to save and restore the line that DATA will read from before you do a RESTORE you can get that from the 2 byte SYSVAR at 23639

Image
Image
User avatar
Jbizzel
Dynamite Dan
Posts: 1537
Joined: Mon May 04, 2020 4:34 pm
Location: Hull
Contact:

Re: getting the true length of a string stored in an array

Post by Jbizzel »

I've never used RESTORE to do anything cool like this. I need to read more about it I think. Very interesting, thank you.
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: getting the true length of a string stored in an array

Post by ParadigmShifter »

I've worked out what the issue was when I tried to do the lookup version of fizbuzz with arrays instead of data.

Until you assign to a string array, it is "" which is fine.
As soon as you assign anything to it it sets length to the max, pads with spaces (so any subsequent appends will silently dump the string you try and append to an array entry I think... which was the issue I came up against).
As soon as you assign to an array slot it's no longer "" so you can't use that to check if you didn't append anything to it (which is how that version of fizzbuzz works).

BBC and Amstrad Basic restricted strings to length 255 I think and had a byte count before the string data IIRC, so everything worked (unless you wanted a string of length 256+).

BBC arrays (and maybe Amstrad ones) used 0 as an index as well and allocate 1 more entry than you ask for as well (which can be useful I suppose but if it's zero based they should probably have done the sensible thing and only allowed indices from 0 to size-1... that would cause incompatibilities with other BASICs though which assume indices start from 1 (which is daft anyway, programmers start counting from 0) :)

I think Pascal allows you to set the staring index for arrays (which is best of both worlds in a way but has a runtime performance cost).

Strings in BASIC are slow anyway since if you resize one it tries to compact the memory usage IIRC.

I'm not a fan of BASIC anyway ;) At least in ASM you can implement strings however you want. On a non 8-bit machine I would use C or a higher level language of course (although string and memory handling in C leaves a lot to be desired).
sn3j
Manic Miner
Posts: 501
Joined: Mon Oct 31, 2022 12:29 am
Location: Germany

Re: getting the true length of a string stored in an array

Post by sn3j »

Here's another idea. You can use VAL$ to read a string from an array.

Code: Select all

  10 DIM a$(3,10)
  20 FOR i=1 TO 3
  30 READ s$: LET a$(i)=CHR$ 34+s$+CHR$ 34
  40 NEXT i
  50 FOR i=1 TO 3
  60 PRINT AT 10+i,0; BRIGHT 1;VAL$ a$(i)
  70 NEXT i
 101 DATA "Blue"
 102 DATA "Green"
 103 DATA "Yellow"
 
How it works:
The array keeps its strings delimited by double quotes, like so:
  • "Blue".... (using dots as spaces here)
  • "Green"...
  • "Yellow"..
Now VAL$ looks at the array entry, discards the spaces and returns the string inside the quotes.
I think this could be an interesting topic to discuss with an upcoming Spectrum user. (And more in general, interpreted vs compiled languages.)
Happy coding.
POKE 23614,10: STOP      1..0 hold, SS/m/n colors, b/spc toggle
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: getting the true length of a string stored in an array

Post by ParadigmShifter »

Image

EDIT: Unless you want to post some C pseudocode explaining it all that is... probably won't know what it is useful for regardless ;)

OP should probably post what they were actually trying to do rather than a toy example showing how ZX Basic is busted so we can give better advice on what to do in basic instead anyway.

EDIT2: They are probably looking for the RESTORE solution - the ones involving packing extra stuff into arrays is just too fiddly to do in BASIC. Only problem with the RESTORE method is the next DATA pointer is wiped when you do a RESTORE but I showed a way to stash and restore (no pun intended) that.

RESTORE method has the problem that you then have magic line numbers of course. Which you can fix with variables but again more tedium/runtime cost/more variable storage required...

EDIT3: My fizzbuzz code has a spurious STR$ which is not needed I always forget basic will coerce a number into a string for output ;) Although C# does that too I guess.
User avatar
uglifruit
Manic Miner
Posts: 703
Joined: Thu Jan 17, 2019 12:41 pm
Location: Leicester
Contact:

Re: getting the true length of a string stored in an array

Post by uglifruit »

I really like the use of VAL$ use @sn3j . Very good.

Here's a nice way of storing the length as the last character. Much like Jim's method, but using the character number, but without having to interpret the numbers stored as tho digits of ASCII.

Code: Select all

10 DIM a$(3,10)
20 FOR a=1 TO 3
30 READ b$
40 LET a$(a)=b$
50 LET a$(a,10)=CHR$(LEN b$)
60 NEXT a

100 FOR a=1 TO 3
110 LET b$=a$(a)
120 PRINT BRIGHT 1; b$( TO CODE a$(a,10));BRIGHT 0,"Length ";CODE a$(a,10)
130 NEXT a

1000 DATA "red","yellow","blue"
CLEAR 23855
User avatar
uglifruit
Manic Miner
Posts: 703
Joined: Thu Jan 17, 2019 12:41 pm
Location: Leicester
Contact:

Re: getting the true length of a string stored in an array

Post by uglifruit »

I like that if it's adding to the array, it only adds one byte per item.


A quick reworking of @sn3j's VAL$ technique means you could just append a quotation mark at the storage time, then add one at decoding time if there's a need to keep the array as short as possible. With the caveat that it'd be a tad slower to decode than storing both quotation marks in the array.

Code: Select all

10 DIM a$(3,10)
20 FOR a=1 TO 3
30 READ b$
40 LET a$(a)=b$+""""
50 NEXT a

100 FOR a=1 TO 3
110 LET b$=""""+a$(a)
120 PRINT BRIGHT 1; VAL$ b$;BRIGHT 0,"Length ";LEN VAL$ b$
130 NEXT a

1000 DATA "red","yellow","blue"

Note that """" is the awkward way of having a single quotation mark inside quotation marks in BASIC



Image
CLEAR 23855
sn3j
Manic Miner
Posts: 501
Joined: Mon Oct 31, 2022 12:29 am
Location: Germany

Re: getting the true length of a string stored in an array

Post by sn3j »

ParadigmShifter wrote: Tue Dec 12, 2023 8:26 am EDIT: Unless you want to post some C pseudocode explaining it all that is... probably won't know what it is useful for regardless ;)
Erm, I'll try to explain it in words. Let's look at: VAL$ s$
  • The content of s$ is placed into a fresh space in the work area, followed by a terminating symbol.
  • The expression parser is invoked with the starting address of this space.
  • The expression parser evaluates the string, symbol for symbol, until it reaches the terminating character.
  • If no syntax errors happened, there will be one result of type 'string' left on the calculator stack.
For example, if s$ contains the string: "Hello" + CHR$ 32 + "Speccy" + "!"
The whole thing will be interpreted as if you typed it at the command prompt, and so the result you get is: Hello Speccy!

The issue with the RESTORE only solution is that you can't change the strings at runtime, unless of course you poke into the DATA statements which I think is no good practice.
POKE 23614,10: STOP      1..0 hold, SS/m/n colors, b/spc toggle
User avatar
Red Zebra
Drutt
Posts: 36
Joined: Fri Jan 20, 2023 7:53 am

Re: getting the true length of a string stored in an array

Post by Red Zebra »

It depends on what you plan to do with the string array, so this may not be applicable: but a simple way to do it would be just to keep the strings in one array and their lengths (at the same index) in another. It uses up more memory, but you also save memory by not needing a custom length routine.

Code: Select all

10 DIM a$(3,12): DIM a(3)
20 FOR x = 1 to 3
30 READ t$
40 LET a$(x) = t$
50 LET a(x) = LEN t$
60 NEXT x
70 FOR x = 1 to 3
80 PRINT BRIGHT 1; a$(x)(1 TO a(x)); BRIGHT 0; TAB 12; "Length:"; a(x)
90 NEXT x
3000 DATA "one","fives","twenty-two"
User avatar
1024MAK
Bugaboo
Posts: 3123
Joined: Wed Nov 15, 2017 2:52 pm
Location: Sunny Somerset in the U.K. in Europe

Re: getting the true length of a string stored in an array

Post by 1024MAK »

Red Zebra wrote: Wed Dec 13, 2023 5:57 pm ...: but a simple way to do it would be just to keep the strings in one array and their lengths (at the same index) in another.
Which is what I meant in my first post in this topic ;-)

Mark
:!: Standby alert :!:
“There are four lights!”
Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb :dance
Looking forward to summer later in the year.
User avatar
Red Zebra
Drutt
Posts: 36
Joined: Fri Jan 20, 2023 7:53 am

Re: getting the true length of a string stored in an array

Post by Red Zebra »

Oops! I skimmed the thread to check if it had been suggested already, but I seem to have missed it.
User avatar
1024MAK
Bugaboo
Posts: 3123
Joined: Wed Nov 15, 2017 2:52 pm
Location: Sunny Somerset in the U.K. in Europe

Re: getting the true length of a string stored in an array

Post by 1024MAK »

Red Zebra wrote: Thu Dec 14, 2023 8:35 am Oops! I skimmed the thread to check if it had been suggested already, but I seem to have missed it.
Don't worry, be happy! I'm happy that at least one other person thinks its a reasonable idea :lol:

Mark
:!: Standby alert :!:
“There are four lights!”
Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb :dance
Looking forward to summer later in the year.
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: getting the true length of a string stored in an array

Post by ParadigmShifter »

Here's a more useful program demonstrating the RESTORE method (but yeah, it does only work with constant string data)

Image

Works out the day of the week for any date in the Gregorian calendar (year 1720+ I think).

EDIT: Probably better to do the validation in the subroutine and return something like d=-1 for an invalid date though.

EDIT: Is there a way to produce a text file from the basic program in ZX Spin???

Weekday of Christmas this year

Image

FN m(a,b) returns a MOD b

It's important to get the 12 numbers after the number of days in each month (non leap years) correct in line 9000 otherwise it won't work, obviously ;)

Subroutine at line 1010 returns day of the week in d, 0 = Sunday, 1 = Monday, etc.

Algorithm:

https://en.wikipedia.org/wiki/Determina ... 's_methods
Post Reply