x
Solved

# Array ---> string?

Posted on 2000-03-18
Medium Priority
438 Views
Hi,
For example:
var
a: array[1..1024] of char;
s: string;
What is the fastest way to convert the chars in the array into the string variable, ie. s:=a[1]+a[2]+a[3].......+a[1024];
I know a for loop may help, but I suppose it's a time consuming process if the array is very large, say, [1..1024000].
So is there a function or procedure can do this??
0
Question by:nyt
• 5
• 4
• 3
• +6

Expert Comment

ID: 2631254
lestining ...
0

Expert Comment

ID: 2631261
for I := Low(a) to High(a) do begin
S := a[I];
Application.ProcessMessage;
end;

ProcessMessage will avoid system buissy

Regards,
Hamid

0

Expert Comment

ID: 2631262
for I := Low(a) to High(a) do begin
S := S + a[I];
Application.ProcessMessage;
end;

ProcessMessage will avoid system buissy

Regards,
Hamid

0

LVL 27

Expert Comment

ID: 2631295
hi nyt,

SetString(s,PChar(@a),sizeOf(a));

sample

var
a: array[1..1024] of char;
s : String;

procedure Init_a;   //just for init the array
var I : Integer;
begin
for i := low(a) to high(a) do
a[i] := Chr((i mod 26) + 65);  //only capital letters
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
init_a;
SetString(s,PChar(@a),sizeOf(a));
memo1.text := s;  //just for output
end;

meikl
0

Expert Comment

ID: 2631362
for I := Low(a) to High(a) do begin
S := S + a[I];
Application.ProcessMessage;
end;

ProcessMessage will avoid system buissy

Regards,
Hamid

0

LVL 2

Accepted Solution

kubeerja earned 200 total points
ID: 2631443
why dont use S:=A ;
string in delphi is an array of char, so when you say
a: array[1..1024] of char;
this equals A : String[1024] ;
actually you can use A directly as string and say for example  label1.Caption:=A ;
0

LVL 20

Expert Comment

ID: 2632135
meikl is right. And kubeerja is right, too - but only in some parts of his comment.
The easiest way is to do this:

var s1 : string;
arrCh : array [1..1024] of char;
begin
s1 := arrCh;

But the reason why you can do this is NOT that a Delphi string would be equal to an array of char - it is NOT!!!
If you define "String[1024]", this is something like "record length: byte; data: array [1..1024] of char end;". You see the difference? Delphi's short strings have a length byte in the beginning.
And normally we should even forget short strings at all. We should be using long strings, that is simply "string". And a string is a quite complex structure, that Delphi handles completely automatically. E.g. if you do this:

var s: string;
begin
s := 'test';

Delphi now allocates memory for this string PLUS size for a little record, puts the characters "test" to the allocated memory and fills the record. In the record there are integer (32-bit) values for the size of the string (so long strings can be 4 GB long), for the allocation size and for the reference count. Yes, Delphi long strings are being administered by Delphi using reference counting, just like COM objects are, but much faster.

If you do "stringVar := pcharVar" or "stringVar := arrayOfCharVar", Delphi accepts this as a valid syntax and does ALL the work for you. It's the fastest you can do. It will result in a call to SetString. So in the end it is equal to meikl's suggestion, but easier to write/understand.

Using a loop like Hamid suggested would work alright, but is several times slower, because Delphi has to reallocate the string several times.

0

LVL 2

Expert Comment

ID: 2632198
Another way...

Use Setlength to allocate the string memory in one shot.

Use the built-in move procedure to copy the memory efficiently.

This will be the fastest for long multimegabyte data.

(well not quite, see..
http://www.econos.com/optimize/
for move and alignment tricks)

const
MaxDataLength=1024;
var
Data:array[0..MaxDataLength-1] of char;
///note Data is zero based in my example
DataLength:word=973;
///maybe data is shorter than 1024
TargetString:string;

....

assert(
DataLength<=MaxDataLength,
'Length Error');
///check

setlength(TargetString,datalength);
move(
data[low(Data)],
///low returns zero here
TargetString[1],
datalength);
....

also, if you do use the simple mechanism
TargetString:=pChar(@Data[0]);
///or similar, I dont have delphi handy
Be sure to preceed it by...
Data[low(Data)+DataLength]:=#0;

This is because the length of a pchar string is set by the terminating null (#0).

-Alex
0

LVL 20

Expert Comment

ID: 2632984
Hi Alex, I'm sorry to say, but your suggestion is NO WAY faster than simply assigning "strVar := arrOfCharVar". You can believe me, I've just done some timing tests. Your suggestion needs EXACTLY the same time as the simple assignment (or SetString) needs. So no difference - so no reason to go the complicated way.

>> Be sure to preceed it by...
>> Data[low(Data)+DataLength]:=#0;
>> This is because the length of a pchar string is set by the terminating null (#0).

NO! Delphi does that for you. Well, if you use the simple assignment (or SetString), THEN Delphi does it for you. It's different of course, if you use Move, then you have to look for that #0 yourself.

0

LVL 9

Expert Comment

ID: 2633027
hi nyt.

-------
var
a: array[1..1024] of char;
s: string;

begin
SetLength(S,1024);
move(A,pointer(S)^,1024);
....

Is it applicable?

Cheers,
Igor.

0

LVL 5

Expert Comment

ID: 2633181
Hi Madshi :) been a while...  Anyway, I just wanted to put in my 2 cents on this.  This seems like basic stuff to me, and I completely agree with Madshi.  Character arrays are completely assignment compatible with strings....  why would you want to do any of this hocus pocus stuff when you can just do s:=a; ???  Am I missing something?

Heath
0

Expert Comment

ID: 2633200
lestining ,,,,
0

LVL 20

Expert Comment

ID: 2633271
Hi Heath!  (-:  How are things goin?
0

LVL 5

Expert Comment

ID: 2633302
Pretty good.  I am still working for the same web development company, but my position changed about 4 months ago from Network Administrator to Network Administrator/Lead Programmer because of a couple of programmers leaving the company...  It is really fun having 2 jobs, NOT :P  At first I was just sort of helping with the programming and stuff, but after those other guys left I was like the only programmer here.  I have been meaning to drop in here but just keep getting buried in work.  But now that I have a little free time I will be able to play with Delphi again (they just hired a couple of new programmers who seem to be doing well).  Cold Fusion is cool and all, but it isnt Delphi :)

Heath
0

LVL 20

Expert Comment

ID: 2633437
Nice to hear. I hope your earnings have changed along with your position?   =:O))
0

Author Comment

ID: 2634676
Most of the answers work.  I just accept the comment submitted first as the answer.
Thank you all.
0

LVL 2

Expert Comment

ID: 2637442
Well, I can see we are flogging this problem beyond the realms of utility, but I cant resist another comment...

Using the crude (but simple) timing code below, I measure assigning the char array data (300 mbytes) (D5 on a P2-500 machine with 1GByte ram)
We Compare
....
bigstring:='';
setlength(BigString,DataLength);
move(BigCharArray[low(BigCharArray)],
BigString[1],
datalength);
....
and the simpler syntax
....
bigstring:='';
bigstring:=BigCharArray;
....

For Big arrays (300 Mbytes) the setlength-move is over 2 times faster than the simplest syntax. (3.8 secs vs 8.5 secs)

For midsize arrays (50 Mbytes) the setlength-move is about 3 times faster than the simplest syntax.

For short arrays (1 Mbyte) the setlength-move is about 2.5 times faster than the simplest syntax.

So unlike Madshi, I do find a real speed difference with a single cpu. A major advantage with using the setlength-move is that you can then apply optimised moves, especially if you have multiple processors. Another advantage is that this makes a good way to copy sub regions from your char array, without the creation of hidden temporary strings which the use of 'copy/delete' would incur(how much?).

The thread safe string stuff can also slow string things down.

Also, suprisingly (to me anyway)
....
BigString:=pchar(@BigCharArray[0]);
....
is consistently faster than
....
bigstring:=BigCharArray;
....
(but not as fast as SetLength-Move)
The pchar approach has to scan the string to find a null, but why is it faster? I dont know.
---------------------------------------
This is the ez-timing code
(you can use gettickcount instead of timegettime), or the QueryPerf.. functions
---------------------------------------
const
siz=1048576*300;
DataLength=siz;
var
BigCharArray:array[0..siz-1]of char;
BigString:string;
t0:integer;

procedure TForm1.Button1Click(Sender: TObject);
begin
bigstring:='';
t0:=timegettime;
setlength(BigString,DataLength);
move(
BigCharArray[low(BigCharArray)],
BigString[1],
datalength);
label1.caption:=inttostr(timegettime-t0);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
bigstring:='';
t0:=timegettime;
bigstring:=BigCharArray;
label1.caption:=inttostr(timegettime-t0);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
n:integer;
begin
t0:=timegettime;
for n:=0 to siz-1 do BigCharArray[n]:=char(random(64)+32);
label1.caption:=inttostr(timegettime-t0);
end;
---------------------------------------
---------------------------------------
Alex

ps My previous advice to ...
>>Data[low(Data)+DataLength]:=#0;
was because many times (and in the example I gave) the DataLength might not be equal to the ArraySize. It is a useful trick for copying substrings out of long (multimegabyte) buffers, (but you might want to save and restore the previous buffer value).

All these timings were sensitive to relative cache allignment, (aliasing of cache addresses occurrs since the buffers are a power of two in size),
there is a 50% speedup change to be had if you vary the data allignment in dword chunks over the size of a cache line.

0

LVL 2

Expert Comment

ID: 2637490
For kicks I timed the 1024 byte case
using the clock cycle counter on the >=pentium cpus.
(*
function  RDTSC:int64;
var
tscrec:record
case byte of
1:(tsc:int64);
2:(tsclo,tschi:longint);
end;
begin
asm
db \$0f, \$31
mov tscrec.tsclo, eax
mov tscrec.tschi, edx
end;
result:=tscrec.tsc;
end;
*)

"SetLength;Move" is >2x faster, on this machine than "string:=array" for tiny strings.

To do timings like this you really need to do stuff like turning off the dram refresh.

Alex
0

LVL 20

Expert Comment

ID: 2637515
Hi Alex...   :-)

Well, I've not copied one mega-sized string, but instead I've copied a mid-sized string 10000 times or so. Don't know why I didn't have any timing differences there.

However, I can explain, why Move is faster than the assignment:
If you do the assignment, Delphi looks through the array to find the first #0 character to find the real length of the string. This search for the #0 character is most probably the delay your timing test has shown.

Okay, so if you need to copy a 300 MB string, Move is faster. Okay...  :-))  Just joking. But this is meant serious: Most of the time, when you want to convert a pchar or an array of character to a Delphi string, you WANT Delphi to look for that #0 character, right? Because pchar is defined this way. Say, Alex, have you tried SetString, as meikl has suggested? Because there you give in the length, so Delphi doesn't have to search. Probably you have then the same speed as Move again...
0

## Featured Post

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.