Link to home
Start Free TrialLog in
Avatar of nyt
nyt

asked on

Array ---> string?

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??
Thanks in advance!
Avatar of HamidHossain
HamidHossain

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


ProcessMessage will avoid system buissy

Regards,
Hamid

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


ProcessMessage will avoid system buissy

Regards,
Hamid

Avatar of kretzschmar
hi nyt,

what about

  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
for I := Low(a) to High(a) do begin
  S := S + a[I];
  Application.ProcessMessage;
end;


ProcessMessage will avoid system buissy

Regards,
Hamid

ASKER CERTIFIED SOLUTION
Avatar of kubeerja
kubeerja

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.

Regards, Madshi.
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
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.

Regards, Madshi.
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.
   
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
lestining ,,,,
Hi Heath!  (-:  How are things goin?
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
Nice to hear. I hope your earnings have changed along with your position?   =:O))
Avatar of nyt

ASKER

Most of the answers work.  I just accept the comment submitted first as the answer.
Thank you all.
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.

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
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...