SRL Archive - Discussions & Debates

Using String as an Array.


Awkwardsaw

2013-07-29 22:03:21

For some unknown reason the discussion using string as an array has popped up in the Skype group.
Through random experiments, I've noticed that if you run this:
program new;
var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o'];
s := '';

writeln(length(c));
setlength(s, length(c));
for i := 0 to 4 do
begin
s := s + c[i];
writeln(s);
end;
Delete(s, 1, 1);
writeln(s[1]);
end.

it will result in something like
formWh
formWhe
formWhel
formWhell
formWhello

As if Simba automatically fills in the null elements. If you setlength() in the loop using "setlength(s, i + 1);" it will instead make the first element(s[1]) the length of the array,
program new;
var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o'];
s := '';

writeln(length(c));
for i := 0 to 4 do
begin
setlength(s, i + 1);
s := s + c[i];
writeln(s);
end;
end.

resulting in:
5
5h
5he
5hel
5hell
5hello

And finally, if you remove setlength all together, the first element of 's' is actually the first element of the char array. This is probably common sense to everyone, but it strikes me as interesting, since I've never really messed with this. Thoughts?

Turpinator

2013-07-29 22:09:06

However…
program new;
var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o', '!'];
s := '';

writeln(length(c));
for i := 0 to 4 do
begin
setlength(s, i + 1);
s := s + c[i];
writeln(s);
end;
end.
Returns
6
6h
6he
6hel
6hell
6hello

And loop bounds of 1 to 4 (or whatever), yields
6
6
6
6
6
i presume it is due to the fact that a string isnt a true char array compared to a cstring.

Awkwardsaw

2013-07-29 22:09:53

From: Turpinator
However…
program new;
var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o', '!'];
s := '';

writeln(length(c));
for i := 0 to 4 do
begin
setlength(s, i + 1);
s := s + c[i];
writeln(s);
end;
end.
Returns
6
6h
6he
6hel
6hell
6hello


you forgot to set the length in the for loop
edit: Oh, I guess that's the point. WHAT IS HAPPENING

Brandon

2013-07-29 22:46:20

Edit. Wanted to update this post for the most recent Simba:


program new;
var
s : string;
begin
cleardebug;
setlength(s, 50);
writeln(s);
end.

EDIT:

One solution in LAPE is to memset the string using the following (Don't know any solution for PS):


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Begin
Ptr^ := Value;
End;
End;


var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o'];
s := '';

writeln(length(c));
setlength(s, length(c));
MemSet(@s, 0, length(c));

for i := 0 to 4 do
begin
s := s + c[i];
writeln(s);
end;
Delete(s, 1, 1);
writeln(s[1]);
end.


Run the above. You'll notice that what happens is that strings in Simba is not INITIALIZED to any default values. What I noticed happening in the latest simba is that it is taking the value of whatever is being printed in the console. You can tell by changing the string's length above..
However, this does not happen in Lape. So clearly I am wrong. Running the code on the OP happens in BOTH Lape and PS and the only logical things I can come up with again since it always involves the string length is:

Buffer overflows, underflows and the following:


*sigh* here goes.. the history of strings..

Ok so in C/C++, strings have to be null terminated to use functions like:

strlen. What it does is that it counts the amount of characters in a string until it reaches a null char. This determines the length of the string.

Pascal however, came up with the idea to store the length of the string in the first index. Hence why you can't prints S[0] and the length of a PS string is limited to 255 chars not including the first index aka 256. Why? Because the first index is a byte ranging from 0 to 255.

The reason they did this was because appending to a string in C/C++ required that you iterate through every single character in the string to get the length, then to create a new array of new size and then iterate through the string once again up to length, to copy the old chars into the new char array. However, in pascal strings, it already has the length stored so instead, it just makes a new char array of new size and copy the old chars into the new array. No double iteration. Hence why java has something called "StringBuilder" and now the += operator and + operator in java now uses that stringbuilder to prevent double iteration.

Optimization 101 guys.


Calling setlength on a string in PS used to be a problem. In fact, it does nothing to the string though except 0 it out. The problem here is this line though:


writeln(length(c));

Remove it and you'll notice it doesn't print anything. Now remove:

setlength(s, i + 1);

and it'll work as it should. SetLength in this case must only work on arrays and though strings are arrays of chars, since it has to reallocate space and copy the previous string to the newly allocated space, it does NOT copy the first byte of a string aka the length.. because it can't since strings start at index 1. Thus all info is lost in translation and everytime you call setlength, the string's length is actually longer but what is stored is 0. In other words, setlength does not store the length of the string in the first byte/index and so the string things it is a length of 0 when in fact it is larger. Let's just say it's bad language design but has it's benefits when appending to a string < 255 chars total length.

Conclusion: Don't call setlength on strings?