Search code examples
stringdelphifreepascallazarusaddition

Strange behaviour when simply adding strings in Lazarus - FreePascal


The program has several "encryption" algorithms. This one should blockwise reverse the input. "He|ll|o " becomes "o |ll|He" (block length of 2).

I add two strings, in this case appending the result string to the current "block" string and making that the result. When I add the result first and then the block it works fine and gives me back the original string. But when i try to reverse the order it just gives me the the last "block".

Several other functions that are used for "rotation" are above.

//amount of blocks
function amBl(i1:integer;i2:integer):integer;
begin
  if (i1 mod i2) <> 0 then result := (i1 div i2) else result := (i1 div i2) - 1;
end;

//calculation of block length
function calcBl(keyStr:string):integer;
var i:integer;
begin
  result := 0;
  for i := 1 to Length(keyStr) do
  begin
     result := (result + ord(keyStr[i])) mod 5;
     result := result + 2;
  end;

end;

//desperate try to add strings
function append(s1,s2:string):string;
begin
  insert(s2,s1,Length(s1)+1);
  result := s1;
end;

function rotation(inStr,keyStr:string):string;
var //array of chars -> string
    block,temp:string;
    //position in block  variable
    posB:integer;
    //block length and block count variable
    bl, bc:integer;
    //null character as placeholder
    n : ansiChar;

begin
   //calculating block length 2..6
   bl := calcBl(keyStr);
   setLength(block,bl);
   result := '';
   temp := '';
   {n := #00;}

   for bc := 0 to amBl(Length(inStr),bl) do
     begin
       //filling block with chars starting from back of virtual block (in inStr)
       for posB := 1 to bl do
       begin
       block[posB] := inStr[bc * bl + posB];
       {if inStr[bc * bl + posB] = ' ' then block[posB] := n;}
       end;

       //adding the block in front of the existing result string
       temp := result;
       result := block + temp;
       //result := append(block,temp);
       //result := concat(block,temp);

     end;

end;

(full code http://pastebin.com/6Uarerhk)

After all the loops "result" has the right value, but in the last step (between "result := block + temp" and the "end;" of the function) "block" replaces the content of "result" with itself completely, it doesn't add result at the end anymore. And as you can see I even used a temp variable to try to work around that.. doesnt change anything though.


Solution

  • I am 99.99% certain that your problem is due to a subtle bug in your code. However, your deliberate efforts to hide the relevant code mean that we're really shooting in the dark. You haven't even been clear about where you're seeing the shortened Result: GUI Control/Debugger/Writeln

    The irony is that you have all the information at your fingertips to provide a small concise demonstration of your problem - including sample input and expected output.

    So without the relevant information, I can only guess; I do think I have a good hunch though.

    Try the following code and see if you have a similar experience with S3:

    S1 := 'a'#0;
    S2 := 'bc';
    S3 := S1 + S2;
    

    The reason for my hunch is that #0 is a valid character in a string: but whenever that string needs to be processed as PChar, #0 will be interpreted as a string terminator. This could very well cause the "strange behaviour" you're seeing.

    So it's quite probable that you have at least one of the following 2 bugs in your code:

    1. You are always processing 1 too many characters; with the extra character being #0.
    2. When your input string has an odd number of characters: your algorithm (which relies on pairs of characters) adds an extra character with value #0.

    Edit

    With the additional source code, my hunch is confirmed:

    • Suppose you have a 5 character string, and key that produces block length 2.
    • Your inner loop (for posB := 1 to bl do) will read beyond the length of inStr on the last iteration of the outer loop.
    • So if the next character in memory happens to be #0, you will be doing exactly as described above.

    Additional problem. You have the following code:

     //calculating block length 2..6
     bl := calcBl(keyStr);
    

    Your assumption in the comment is wrong. From the implementation of calcBl, if keyStr is empty, your result will be 0.