1
votes

I have written a program in Delphi to compute, display and save a Pascals' triangle for a user-defined number of rows. It works fine (displays the triangle, and allows me to save it), except that it comes up with an access violation at the end! Here is the message:

Access violation at address 004031DB in module 'Project1.exe'. Read of address 00000000.

I have a 2D dynamic array in the procedure but I release the memory at the end (:= nil). Why is it still giving me an access violation? Very frustrating!

I searched the archives for an answer but could not find an appropriate answer. Any help will be greatly appreciated.

Here is the code (I was a little hesitant as there is a bit of code:

 procedure TForm1.btnPTClick(Sender: TObject);
 var
   I, J, K, N, MidCol: integer;
   PT: array of array of integer;
   Row: string;
 begin
   K := StrToInt(lblNumRows.Text);
   N := StrToInt(lblNumRows.Text);//# values in row = row number

   try
       //initiatlize the array
       SetLength(PT, K, (N*2)-1);
       for I := 0 to K-1 do
         for J := 0 to (N*2-1) do
           PT[I,J] := 0;

       MidCol := (N*2 div 2)-1;//MidCol already 0-based
       for I := 0 to K-1 do
         begin
           if (I = 0) then
             PT[I,MidCol] := 1//first row gets 1 in the middle column
               else if I = 1 then
                 begin
                   PT[I,MidCol-1] := 1;
                   PT[I,MidCol+1] := 1; //first and last value in second = 1
                 end
            else //if any other row
              begin

                //Middle column
                PT[I, MidCol] := PT[I-1,MidCol-1] + PT[I-1,MidCol+1];
                //right triangle
                for J := MidCol+1 to (N*2-1) do
                  begin
                    if (PT[I-1, J-1]=1) then//if already at the end of prev row
                      begin
                        PT[I,J] := 1;
                        break;
                      end
                    else
                      PT[I,J] := PT[I-1,J-1] + PT[I-1,J+1];
                  end;
                //left triangle
                for J := MidCol-1 downto 0 do
                  begin
                    if (PT[I-1, J+1] = 1) then //if already at the end of prev row
                      begin
                        PT[I,J] := 1;
                        break;
                      end
                    else
                      PT[I,J] := PT[I-1,J-1] + PT[I-1,J+1];
                  end;
              end;
         end;

         //now add the pyramid to the memo
         Application.ProcessMessages;
         for I := 0 to K-1 do
           begin
             Row := '';
             for J := 0 to N*2-1 do
               begin
                 if (PT[I,J] = 0) then Row := Row + ' '
                 else Row := Row + IntToStr(PT[I,J]);
               end;
             Memo.Lines.Add(Row);
           end;

   finally
     SetLength(PT, 0, 0);
   end;
 end;
2
It is completely impossible to say without seeing your code. Are you sure you aren't writing to out-of-bound array indices? Maybe you use a previously-freed (or not yet created) 'object'?Andreas Rejbrand
@user1505202: I would remove the := nil on the array since it is an object managed by the language and is properly disposed when not needed anymoreAlexSC
the error might be because you are trying to free the same object twice or it is already freed?user1175743
for J := 0 to (N*2-1) do you have passed the high bound. Overwriting memory. There can be other...Sertac Akyuz

2 Answers

7
votes
Read of address 00000000

This indicates that you are trying to access memory using a pointer that is nil. To know why that is so one would need code. At present only you have code, and so only you can explain.

Run the program in the debugger. Enable Debug DCUs in case the error is raised in RTL/VCL code. Ensure that the debugger is configured to break on exceptions. The run your program and trigger the error. The debugger will show you which nil object is being de-referenced. Then you have to work out why that reference is nil.

The code you have added to the answer has a buffer overrun which could certainly explain the problem. Your SetLength is incorrect and should read:

SetLength(PT, K, N*2);

Your code writes to memory out-of-bounds and so corrupts the heap. You should ask the compiler to produce runtime checks on your array bounds. Enable the compiler's range checking option. Had you done so, you would have found this error yourself.

For what it is worth you do not need that try/finally block since the compiler will automatically insert a hidden block. There's no need for two when one suffices. A dynamic array is a managed type whose memory is disposed when the variable leaves scope.

1
votes

Press F7, to start the project in the debugger. Look in the main menu for the "Find Error..." option (in Delphi 7 it was under the Search menu) then enter the address from the exception: 004031DB. This will show you the exact line where the exception occurred. Read of address 00000000 generally indicates you are using a pointer that has a nil value.