Search code examples
delphirecursionmergesortdelphi-xe

Invalid pointer operation; Recursive Merge Sort


I've attempted to implement a merge sort for strings however I cannot perform the recursive part and I get the error "Invalid Pointer Operation"

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var i : Integer;
const MyArray : array[1..5]of string = ('hi', 'zebra', 'apple', 'Xylophone', 'dog');

Procedure merge(result, left, right : array of string);
var i, i1, i2 : Integer;
begin
  i1 := 0;
  i2 := 0;
  for i := 0 to Length(result) do
  begin
    if (i2 >= Length(right)) or (i1 < Length(left)) and (StrComp(PChar(left[i]), PChar(right[i2])) < 0) then
    begin
      result[i] := left[i1];
      inc(i1);
    end
    else
    begin
      result[i] := right[i2];
      inc(i2);
    end;
  end;
end;


Procedure mergeSort(OriginalList : array of string);
var left, right : array of string;
    i : Integer;
begin
  if (Length(OriginalList) >= 2) then
  begin
    setlength(left, length(OriginalList) div 2);
    setlength(right, length(OriginalList) - (length(OriginalList) div 2));
    for i := 0 to Length(left) do
    begin
      left[i] := OriginalList[i];
    end;
    for i := 0 to Length(right) do
    begin
      right[i] := OriginalList[i + Length(OriginalList) div 2];
    end;
    mergeSort(left);
    mergeSort(right);
    merge(OriginalList, left, right);
  end;
end;

begin
  writeln('The data before sorting: ');
  for i := low(MyArray) to High(MyArray) do
  begin
    write(MyArray[i]+' ');
  end;
  writeln;
  mergeSort(MyArray);
  writeln('The data before sorting: ');
  for i := low(MyArray) to High(MyArray) do
  begin
    write(MyArray[i]+' ');
  end;
  readln;
end.

On the line in the mereSort function where I recall the merge sort function on the arrays "left" and "right", I get the error message but I don't quite understand why?


Solution

  • There are many different things wrong with this, hopefully these points will help you in the right direction.

    Problems with Array Indexes

    You are indexing beyond the end of your arrays: Dynamic arrays are indexed starting from zero so the line

        for i := 0 to Length(left) do
    

    should be

        for i := 0 to Length(left) - 1 do
    

    or you can use

       for i := Low(left) to High(left) do
    

    As you did later.

    I would recommend you choose a standard form and use it consistently, and also that you avoid declaring constant arrays with non-zero based indexing unless you have good reason, this way you can use the same forms consistently or change the type of array later without running into trouble

    This first fix will stop your program crashing, but you'll notice your sort code isn't changing anything...

    Problems with parameter passing

    Delphi has several different ways to pass parameters into procedures:

    procedure doSomething(a : array of string);
    procedure doSomething(var a : array of string);
    procedure doSomething(out a : array of string);
    procedure doSomething(const a : array of string);
    

    These determine how what happens inside the procedure can affect the original variable passed

    This is something you will need to understand, read up in the documentation: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Parameters_(Delphi)

    There is IMO some very confusing behaviour and syntax relating to array parameters and a lot of stuff that seems intuitive is not allowed especially with XE/older version, its worth reading the documentation about the standard data types

    In the current state, your merge procedure will have no effect because it only operates on a new copy of the array you pass in, which you have also declared as constant

    Other

    I would avoid the use of result as a procedure parameter since this is the name used for function return values, it seems like asking for trouble to use it like that.

    PS: I haven't looked at the logic of the merging, just the basic language mistakes