TStringList .add produces duplicates from random function
Having a problem I can't seem to put my finger on. I am trying to gather strings (random code with letters and numbers) from a function call and place into my TStringList variable. Relevant code is below.
If I run a test, the strings repeat for a given amount of time then a new one is produced. If I introduce a sleep(xx) or showmessage command to happen after each time a code is produced (see 'edits' below) it copies/returns to memo fine and everything looks fine. If I remove the 'delay' I get repeats from function again.
The part of function to add to TStringList:
..
AddToMemo:=TStringList.Create;
AddToMemo.Clear;
AddToMemo.Sorted:=False;
for loop := 1 to totalamount do
begin
sResult:=MakeCode(charsp开发者_StackOverflow中文版ercode, cbUpperLowerCase, cbAvoidChars, customchars);
Sleep(50);
// (or):
//ShowMessage(sResult);
// ^ If I leave a Sleep or ShowMessage in, I can see sResult just fine and
// program works fine - results in memo are correct as well. If I remove
// it, I get repeated entries.
AddToMemo.add(sResult+IntToStr(loop));
// If I remove "sResult+" from AddToMemo.add the ".add"
// works - shows loop numbers in my updated memo
// If left in, I see one code (1st one produced) and no
// appended number at all in Memo produced.
end;
Result:=AddToMemo;
end;
Edit: As I mention below if I leave a ShowMessage or Sleep(xx) call in to pause between .add's, it works fine. If I remove it, I get a bunch of duplicate entries in final tmemo. Edit: MakeCode is a function to return a single random string of chars+numbers (A..Z a..z 0..9). It works fine on it's own.
(Edit for Answer 2)
No exceptions showed up.
So if I do not include sleep() it may generate 500 strings but they are all repeats; after a given amount of time it does change. The amount of repeats from the function call decreases as I increase sleep command. At around Sleep(40); it shows up correctly from function. But of course this is time consuming and unacceptable.
The 'guts' of MakeCode()
function MakeCode(CharsPerCode: Integer; bULCase, bAvoidChars: Boolean; sCChars: String): String;
var
i: integer;
s: string;
begin
//(misc stuff here)
begin
randomize;
s[0]:=chr(CharsPerCode);
for i:=1 to CharsPerCode do
repeat
s[i]:=chr(random(128));
until
(s[i] in ['A'..'Z','a'..'z','0'..'9'])
end;
Result:=s;
end;
This is a behavior of Randomize
. The random number generator is initialized by a calculation on the system clock. If you call it in each iteration in a quick loop, it is initialized with the same seed. That's why a Sleep(50)
is changing the outcome. Call randomize for once, for instance, before starting to populate the string list.
...
AddToMemo.Clear;
AddToMemo.Sorted:=False;
Randomize; // <-- possibly here
for loop := 1 to totalamount do
...
function MakeCode(CharsPerCode: Integer; bULCase, bAvoidChars: Boolean; sCChars: String):
...
begin
// randomize; // <-- not here!
s[0]:=chr(CharsPerCode);
The below quote is from the Delphi documentation:
Do not combine the call to Randomize in a loop with calls to the Random function. Typically, Randomize is called only once, before all calls to Random.
Without seeing what MakeCode() is actually returning in sResult
, my guess would be that sResult
contains non-printable control characters (null characters in particular) that cause the Memo or even the RTL to skip subsequence characters.
You need to show some more Code, evtl. MakeCode. I would try the same with a constant String in sResult without MakeCode, do you get the same? try something like:
for loop := 1 to totalamount do
begin
try
sResult:=MakeCode(charspercode, cbUpperLowerCase, cbAvoidChars, customchars);
AddToMemo.add(sResult+IntToStr(loop));
except on e: exception do
showmessage(e.message);
end;
end;
Do you get any exceptions?
精彩评论