Delphi Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me

The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.

Go Back   Dev Shed ForumsProgramming Languages - MoreDelphi Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old August 1st, 2012, 07:44 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Invalid pointer problem

I am getting an "Invalid pointer operation" exception, but it isn't clear why I am getting this exception. Basically, I call a function from my main unit, it computes the value in the function alright, but as it is exiting the function to go back to the main unit, it is raising this exception. I am not trying to free anything or trying to invoking something that might not exist. Don't know what is going on. Here is a snippet of the code:

Main unit:
...
EstimatedValues := Estimate(A, B, C, etc);
ShowMessage(EstimatedValues);
...


Function TForm1.Estimate(A, B, C, etc):string;
...
begin
try
...
finally
Result := ...;
end;
end;


The code in the function works fine (and is accurate) even at the "Results := ..." statement. In fact I can see the Result when I hover over it. When it goes to the last "end," though, and I step over it, it raises this exception.

What could be going on? I am very much a beginner in Delphi, so it is probably something pretty basic, but I am unable to find the answer. So please be patient.

Thanks!

Reply With Quote
  #2  
Old August 1st, 2012, 07:50 PM
majlumbo majlumbo is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2008
Posts: 254 majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level) 
Time spent in forums: 2 Days 23 h 55 m 14 sec
Reputation Power: 5
Quote:
Originally Posted by llaama2012
I am getting an "Invalid pointer operation" exception, but it isn't clear why I am getting this exception. Basically, I call a function from my main unit, it computes the value in the function alright, but as it is exiting the function to go back to the main unit, it is raising this exception. I am not trying to free anything or trying to invoking something that might not exist. Don't know what is going on. Here is a snippet of the code:

Main unit:
...
EstimatedValues := Estimate(A, B, C, etc);
ShowMessage(EstimatedValues);
...


Function TForm1.Estimate(A, B, C, etc):string;
...
begin
try
...
finally
Result := ...;
end;
end;


The code in the function works fine (and is accurate) even at the "Results := ..." statement. In fact I can see the Result when I hover over it. When it goes to the last "end," though, and I step over it, it raises this exception.

What could be going on? I am very much a beginner in Delphi, so it is probably something pretty basic, but I am unable to find the answer. So please be patient.

Thanks!


In this type of case, you really ought to post your actual code. Obviously in the example you posted, there is nothing wrong, but it isn't enough for us to glean what the problem could be.

Please include the code of your function and the entire procedure of where you call it....

Reply With Quote
  #3  
Old August 2nd, 2012, 01:39 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Thanks. I was hesitant to do so because I am still too new to include an attachment. Also, i was worried that there might be too much code. Since I don't want to leave out something that is potentially important, I am including all of the code (a little self-consciously, I might add ). But since I have been muddling along in Delphi, other pointers (no pun intended) to improve my code are most welcome too!

Basically, I want to compute two parameters for a non-linear regression by means of iterating over a range of values for each of the two parameters. I will then pick those values that correspond to the lowest residual sum of squares as the best (least squares) estimates.

Here is my code (in its entirety). I have highlighted the lines where I get the error. Sorry about the lengthy code and thanks in advance for any help! Also, please note that I get the same error message when I have included "ShareMem" in my uses clause. I have also downloaded sometjhing called "FastShareMem" that was supposed to mitigate some issues that ShareMem could not. But I get the same error message.

----------------------------
unit HillSlope;

interface

uses
Sharemem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, Math;

type
THillSlopeRegr = class(TForm)
HelpCmdBtn: TButton;
OpenFileCmdBtn: TButton;
CloseFormCmdBtn: TButton;
ComputeCmdBtn: TButton;
OpenFileEditBx: TEdit;
OpenDialog1: TOpenDialog;
Label1: TLabel;
YesHeadersRadBtn: TRadioButton;
NoHeadersRadBtn: TRadioButton;
GroupBox1: TGroupBox;
Label2: TLabel;
Label3: TLabel;
EC50_LowSpinEdit: TSpinEdit;
EC50_HighSpinEdit: TSpinEdit;
Hill_LowSpinEdit: TSpinEdit;
Hill_HighSpinEdit: TSpinEdit;
Label4: TLabel;
Label5: TLabel;
procedure HelpCmdBtnClick(Sender: TObject);
procedure CloseFormCmdBtnClick(Sender: TObject);
procedure OpenFileCmdBtnClick(Sender: TObject);
procedure ComputeCmdBtnClick(Sender: TObject);
function Estimate(N_EC, N_Hill: integer; X_Array, Y_Array: array of double; EC50_Low, EC50_High, Hill_Low, Hill_High: double; EC50_Incr, Hill_Incr: double): string;
private
{ Private declarations }
public
{ Public declarations }
end;

var
HillSlopeRegr: THillSlopeRegr;

implementation

{$R *.dfm}




procedure THillSlopeRegr.HelpCmdBtnClick(Sender: TObject);
var
S: string;
begin
S := 'This program computes the Hillslope regression for the pair of' + #13#10 +
'input variables, X and Y, where X is the percent animals that ' + #13#10 +
'have shown the required response, and Y is the dose used.' + #13#10 +
'' + #13#10 +
'INSTRUCTIONS:'+ #13#10 +
'1. Upload the input data as a comma-delimited (.csv) file, with' + #13#10 +
' two columns, X and Y, and press the "Compute" button. ' + #13#10 +
'2. Wait for the message "Done!"' + #13#10 +
'3. The results will be in a .csv file, and will be saved in the' + #13#10 +
' same folder as the input file.' + #13#10 +
'4. The output file will contain the input variables, X and Y,' + #13#10 +
' the expected Y values (Y-hat), the lower and upper limits' + #13#10 +
' for the confidence interval (CI) and the prediction interval (PI)';
ShowMessage(S);
end;



procedure THillSlopeRegr.OpenFileCmdBtnClick(Sender: TObject);
begin
if OpenDialog1.Execute then OpenFileEditBx.Text := OpenDialog1.FileName
else ShowMessage('Cannot open file!');
end;



procedure THillSlopeRegr.ComputeCmdBtnClick(Sender: TObject);
var
I,J,K, Posit, N_EC, N_Hill : integer;
Chr: char;
RowData, X_Str, Y_Str, EstimatedValues: string;
X_Value, Y_Value, EC50_Low, EC50_High, Hill_Low, Hill_High, EC50, EC50_Range, EC50_Incr, HillSlope, Hill_Range, Hill_Incr: double;
InputFile, X_List, Y_List, YHat_List, LLCI_List, ULCI_List, LLPI_List, ULPI_List, Output: TStringList;
X_Array, Y_Array, YHat_Array, EC50_Array, Hill_Array, LLCI_Array, ULCI_Array, LLPI_Array, ULPI_Array: array of double;
const Letters = ['A'..'Z', 'a'..'z'];
begin
try
InputFile := TStringList.Create;
X_List := TStringList.Create;
Y_List := TStringList.Create;
YHat_List := TStringList.Create;
LLCI_List := TStringList.Create;
ULCI_List := TStringList.Create;
LLPI_List := TStringList.Create;
ULPI_List := TStringList.Create;
Output := TStringList.Create;

InputFile.LoadFromFile(OpenFileEditBx.Text);
if YesHeadersRadBtn.Checked = True then K := 1
else if NoHeadersRadBtn.Checked = True then K := 0
else ShowMessage('Does your file have headers?' + #13#10 + 'Please answer Yes or No.');
SetLength(X_Array, InputFile.Count - K);
SetLength(Y_Array, InputFile.Count - K);
N_EC := 10;
N_Hill := 10;
EC50_Range := EC50_HighSpinEdit.Value - EC50_LowSpinEdit.Value;
EC50_Incr := EC50_Range/N_EC;
Hill_Range := Hill_HighSpinEdit.Value - Hill_LowSpinEdit.Value;
Hill_Incr := Hill_Range/N_Hill;



for I := K to InputFile.Count-1 do//value of K depends on presence/abssence of headers in input file
begin
RowData := Trim(InputFile[I]);
Posit := Pos(',', RowData) - 1;//excluding the comma
X_Str := '';
for J := 1 to Posit do X_Str := X_Str + RowData[J];
X_Str := Trim(X_Str);
//check if there are any non-numerical data (letters) in the values
for J := 1 to Length(X_Str) do
begin
Chr := X_Str[J];
if Chr in Letters then
begin
MessageDlg('Error! Your file has non-numerical data in row #' + IntToStr(I) + '!', mtError, [mbAbort], 0);
Exit;
end
else continue;
end;
X_Value := StrToFloat(X_Str);
X_Array[I-1] := X_Value;


Y_Str := '';
for J := (Posit+2) to Length(RowData) do Y_Str := Y_Str + RowData[J];
Y_Str := Trim(Y_Str);
//check if there are any non-numerical data (letters) in the values
for J := 1 to Length(Y_Str) do
begin
Chr := Y_Str[J];
if Chr in Letters then
begin
MessageDlg('Error! Your file has non-numerical data in row #' + IntToStr(I) + '!', mtError, [mbAbort], 0);
Exit;
end
else continue;
end;
Y_Value := StrToFloat(Y_Str);
Y_Array[I-1] := Y_Value;

// ShowMessage(FloatToStr(X_Value) + ',' + FloatToStr(Y_Value));

end;

{The formula for the Hillslope regression is y-hat = min + (Max - Min)/(1 + (X/EC50)^Hillslope),
where Min and Max are constrained to 0% and 100%, respectively. This program needs to
iterate for y-hat values through the EC50_Range and Hill_Range, using the EC50_Incr and
Hill_Incr as the respective increments, and then those values of EC50 and Hillslope
are picked as the best estimates that result in the lowest Residual SS, that is:
Sum(Y - y-hat)2.
}

//Obtain the estimated values of EC50 and Hillslope as a single comma-delimited string
EC50_Low := EC50_LowSpinEdit.Value;
EC50_High := EC50_HighSpinEdit.Value;
Hill_Low := Hill_LowSpinEdit.Value;
Hill_High := Hill_HighSpinEdit.Value;
EC50_Incr := (EC50_HighSpinEdit.Value - EC50_LowSpinEdit.Value)/N_EC;
Hill_Incr := (Hill_HighSpinEdit.Value - Hill_LowSpinEdit.Value)/N_Hill;
EstimatedValues := Estimate(N_EC, N_Hill, X_Array, Y_Array, EC50_Low, EC50_High, Hill_Low, Hill_High, EC50_Incr, Hill_Incr); ShowMessage(EstimatedValues);


finally
InputFile.Free;
X_List.Free;
Y_List.Free;
YHat_List.Free;
LLCI_List.Free;
ULCI_List.Free;
LLPI_List.Free;
ULPI_List.Free;
Output.Free;
ShowMessage('Done!');
end;


end;




function THillSlopeRegr.Estimate(N_EC, N_Hill: integer; X_Array, Y_Array: array of double; EC50_Low, EC50_High, Hill_Low, Hill_High: double; EC50_Incr, Hill_Incr: double): string;
var
I, J, K, NumValues: integer;
Min, Max, X_Val, Y_Val, A, B, y_hat, Res_Sq, ResSS, Min_ResSS, EC50, Low_EC50, Low_Hill, Hill: double;
RSS_Array, MinSS_Array: array of double;
EC50_Array, Hill_Array, ResSS_Array: array of array of double;//multiple YHat values for each X value, one for each iteration
YHat_Array: array of array of array of double;
begin
try
Min := 0;
Max := 100;
NumValues := Length(X_Array);
SetLength(ResSS_Array, N_EC+1, 11);//1001*1001 matrix of residual sum of squares - for each X,Y value
SetLength(YHat_Array, NumValues, N_EC+1, N_Hill+1);
SetLength(EC50_Array, N_EC+1, N_Hill+1);
SetLength(Hill_Array, N_EC+1, N_Hill+1);
for I := 0 to N_EC do
begin
for J := 0 to N_Hill do
begin
ResSS_Array[I,J] := 0;
EC50_Array[I,J] := 0;
Hill_Array[I,J] := 0;
end;
end;

for I := 0 to NumValues - 1 do
begin
for J := 0 to N_EC do //1001 iterations to accommodate variations in the EC50 value
begin
for K := 0 to N_Hill do //1001 iterations to accommodate variations in the HillSlope value
begin
YHat_Array[I,J,K] := 0;
end;
end;
end;


//iterate over 1000 Hillslope values nested within 1000 EC50 values

for I := 0 to NumValues - 1 do
begin
X_Val := X_Array[I];
Low_EC50 := EC50_Low;
for J := 0 to N_EC do //1001 iterations to accommodate variations in the EC50 value
begin
Low_Hill := Hill_Low;
for K := 0 to N_Hill do //1001 iterations to accommodate variations in the HillSlope value
begin
y_hat := Min + (Max - Min)/(1 + Power((X_Val/Low_EC50), Low_Hill));
YHat_Array[I,J,K] := y_Hat;
EC50_Array[J,K] := Low_EC50;
Hill_Array[J,K] := Low_Hill;
Low_Hill := Low_Hill + Hill_Incr;
end;
Low_EC50 := Low_EC50 + EC50_Incr;

end;
end;

//now compute ResSS for every combination of EC50 and Hill value
for I := 0 to N_EC do
begin
for J := 0 to N_Hill do
begin
ResSS := 0;
for K := 0 to Length(X_Array) - 1 do
begin
Y_Val := Y_Array[K];
y_hat := YHat_Array[K,I,J];
Res_Sq := Power((Y_Val - y_hat), 2);
ResSS := ResSS + Res_Sq;
end;
ResSS_Array[I,J] := ResSS;
end;
end;

SetLength(RSS_Array, N_EC);
SetLength(MinSS_Array, N_EC);
for I := 0 to N_EC do
begin
RSS_Array[I] := 0;
MinSS_Array[I] := 0;
end;

//find the minimum Res SS in a nested manner
for I := 0 to N_EC do
begin
for J := 0 to N_Hill do
begin
RSS_Array[J] := ResSS_Array[I,J];
end;
MinSS_Array[I] := MinValue(RSS_Array);//array of mimimum SS among Hill values within EC50 value
end;
Min_ResSS := MinValue(MinSS_Array);//minimum SS value


for I := 0 to N_EC do
begin
for J := 0 to N_Hill do
begin
ResSS := ResSS_Array[I,J];
if (ResSS = Min_ResSS) then
begin
EC50 := EC50_Array[I,J];
Hill := Hill_Array[I,J];
end
else continue;
end;
end;

finally
Result := FloatToStr(EC50) + ', ' + FloatToStr(Hill);
end;
end;

procedure THillSlopeRegr.CloseFormCmdBtnClick(Sender: TObject);
begin
HillSlopeRegr.Close;
end;

end.

Last edited by llaama2012 : August 2nd, 2012 at 03:29 PM. Reason: Change in code

Reply With Quote
  #4  
Old August 2nd, 2012, 03:56 PM
majlumbo majlumbo is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2008
Posts: 254 majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level) 
Time spent in forums: 2 Days 23 h 55 m 14 sec
Reputation Power: 5
In my cursory look at the code, I can see one possible issue, but that issue would also put into question your statement that the function returns the correct value.

The piece of code in question is just prior to your finally result := FloatToStr(..).. end;

Code:
for I := 0 to N_EC do
begin
   for J := 0 to N_Hill do
   begin
      ResSS := ResSS_Array[I,J];
      if (ResSS = Min_ResSS) then
      begin
         EC50 := EC50_Array[I,J];
         Hill := Hill_Array[I,J];
      end
      else 
         continue;
   end;
end;


The issue is that ResSS and Min_ResSS are both declared as double. Comparing two floating point values with a simple equal sign is asking for trouble. Delphi has a function called CompareValue that compares single/double/extended (and an overloaded function that compares integer/Int64) values. Using that function would look like this

Code:
for I := 0 to N_EC do
begin
   for J := 0 to N_Hill do
   begin
      ResSS := ResSS_Array[I,J];
      if CompareValue(ResSS, Min_ResSS) = 0 then //Edit:  correction here
      {0  - Equal
       -1 - Less Than
       1  - Greather Than}
      begin
         EC50 := EC50_Array[I,J];
         Hill := Hill_Array[I,J];
      end
      else 
         continue;
   end;
end;


Which brings up the fact that EC50 and Hill can only get values when this particular if statement evaluates true. If it never evaluates true (which as currently coded is a distinct possibility), then they are uninitialized variables. Converting an uninitialized variable, which is what you are doing with FloatToStr(..), would definitely give you the error your experiencing.


Also, Since your Estimate function would probably not be called from other units it should be added to the private section of you form's declaration:
Code:
   procedure HelpCmdBtnClick(Sender: TObject);
   procedure CloseFormCmdBtnClick(Sender: TObject);
   procedure OpenFileCmdBtnClick(Sender: TObject);
   procedure ComputeCmdBtnClick(Sender: TObject);
private
   { Private declarations }
   function Estimate(N_EC, N_Hill: integer; X_Array, Y_Array: array of double; EC50_Low, EC50_High, Hill_Low, Hill_High: double; EC50_Incr,                      Hill_Incr: double): string;
public
   { Public declarations }
end;

Hope this addresses the issue..

Last edited by majlumbo : August 2nd, 2012 at 07:19 PM.

Reply With Quote
  #5  
Old August 2nd, 2012, 04:22 PM
majlumbo majlumbo is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2008
Posts: 254 majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level) 
Time spent in forums: 2 Days 23 h 55 m 14 sec
Reputation Power: 5
Also, one more, un-related, comment concerning the creation of your stringlists and then freeing them.

The safest way to create and then free them is to do so using a try..finally block, which you do use, however improperly.

As an example:
Code:
Var
   SL1, SL2, SL3: TStringList;
begin
   SL1 := TStringList.Create;
   try
     // you can work with SL1 from here down.
      SL2 := TStringList.Create;
      try
         //you can work with SL1 and SL2 from here down
         SL3 := TStringList.Create;
         try
            //work with SL1/SL2 and SL3 from here down
         finally
            SL3.Free;
         end;
      finally
         SL2.Free;
      end;
   finally
      SL1.Free;
   end;
end;

basically after you create the object, put the try..finally block.

To catch errors, you need to wrap the code that may cause an error within the try..except block
Code:
function DivideNums(A, B: Integer): Double;
begin
   try
      Result := A/B;
    except
       on EZeroDivide do
          MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
    end;
end;

So where B is zero, this function would not return a value, but give an error message

Reply With Quote
  #6  
Old August 2nd, 2012, 04:26 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Thanks mailjumbo. Appreciate your reading through my code. However, I am getting the same error even after incorporating both your suggestions. (By the way, it is "if CompareValue(ResSS, Min_ResSS) = 0 then ...", right, and not "if CompareValue(ResSS = Min_ResSS) = 0 then ..."?) In any case, I am still getting the same error.

To investigate the error, I tried to save the result in a text file from the function itself. I know it is computing both parameter values accurately (when I step into the code), but when I try to execute the WriteLn command, it gives me an I/O error (103). And when I remove the textfile part of the code, it is giving the same error of invalid pointer. it even skips the "ShowMessage" command after I call the function.

Also, I thought that CompareValue assumes that the two values are equal if they are "close enough" (whatever that means). I got that from http://www.delphibasics.co.uk/RTL.asp?Name=CompareValue.

Reply With Quote
  #7  
Old August 2nd, 2012, 04:29 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Quote:
Originally Posted by majlumbo
Also, one more, un-related, comment concerning the creation of your stringlists and then freeing them.

The safest way to create and then free them is to do so using a try..finally block, which you do use, however improperly.

As an example:
Code:
Var
   SL1, SL2, SL3: TStringList;
begin
   SL1 := TStringList.Create;
   try
     // you can work with SL1 from here down.
      SL2 := TStringList.Create;
      try
         //you can work with SL1 and SL2 from here down
         SL3 := TStringList.Create;
         try
            //work with SL1/SL2 and SL3 from here down
         finally
            SL3.Free;
         end;
      finally
         SL2.Free;
      end;
   finally
      SL1.Free;
   end;
end;

basically after you create the object, put the try..finally block.

To catch errors, you need to wrap the code that may cause an error within the try..except block
Code:
function DivideNums(A, B: Integer): Double;
begin
   try
      Result := A/B;
    except
       on EZeroDivide do
          MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
    end;
end;

So where B is zero, this function would not return a value, but give an error message


Thanks. Both are good suggestions. I will incorporate them.

Reply With Quote
  #8  
Old August 2nd, 2012, 04:34 PM
clivew clivew is offline
Contributing User
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2006
Location: Carlsbad, CA
Posts: 2,045 clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Week 6 Days 2 h 37 m
Reputation Power: 382
A few of additional coding suggestions, since you invited other comments.
1. Don't put the
Result :=
in the finally block.
The finally block is for making sure resources are cleaned up and the states of any properties, variables etc.
are returned to valid / consistent conditions whether the procedure completes successfully or fails to complete with an exception.
2.
It would be better to breakup those big procedures into multiple smaller ones and call
them in sequence from a master procedure. Easier to read, easier to debug.
IF speed is a concern then the most recent versions of Delphi offer the inline keyword
which will instruct the compiler, if possible, to recombine them during compilation.
3.
Take a look at raising your own exceptions. They will usually give you a better design
than using the MessageDlg / Exit combination.
4.
Delphi does not initialize local variables so that although (in this situation) the following code is very unlikely to fail:
Code:
InputFile := TStringList.Create;
X_List := TStringList.Create;
Y_List := TStringList.Create;
YHat_List := TStringList.Create;
LLCI_List := TStringList.Create;
ULCI_List := TStringList.Create;
LLPI_List := TStringList.Create;
ULPI_List := TStringList.Create;
Output := TStringList.Create;

You should first initialize them all to nil. Otherwise your program will crash in the finally
block when it tries to free the first TStringList that was not created.

HTH

Clive

Reply With Quote
  #9  
Old August 2nd, 2012, 05:26 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Mailjumbo, actually, they turned out to be GREAT suggestions, for my code now works! This is bizzare, but all I did was move my "InputFile := TSrtingList.Create" statement to before the "try" statement as you suggested. Also, I added a try...except...end block to where I call the function "Estimate". My exception handling was that if the function returned nill ('') then let me know by means of a MessageDlg. That was it! And it works now. I wonder why...

Also, I understand Clive's suggestions #1 and #4 (and will incorprate them) but not the other two. I will try to break up my main procedure into smaller parts but I do not understand the inline keyword part. But perhaps it is too advanced for me right now. As for the exception handling, though, I thought using the MessageDlg or ShowMessage was raising my own exceptions. Not sure I understand....

Reply With Quote
  #10  
Old August 2nd, 2012, 05:49 PM
clivew clivew is offline
Contributing User
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2006
Location: Carlsbad, CA
Posts: 2,045 clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Week 6 Days 2 h 37 m
Reputation Power: 382
Yes. Ignore inline for now. There are more important things to get your mind around first.

Exceptions - this is more important!
Do learn about them.
You create your own with code such as this:
Code:
  raise Exception.Create('my error message here');

There are, of course, other variations; but this is the simplest.

The big difference between this and your exit statements is this:
Exit; simply exits the current procedure and the calling procedure will try to continue
from the point at which the the procedure that just exited returns.
An Exception raised will just keep walking up the call stack (without trying to run any intervening code)
until it finds the first Except clause. If it does not find one of yours, then it will
eventually hit the default except clause that Delphi has wrapped round your entire application.

Hope this clarifies a little.

Clive

Reply With Quote
  #11  
Old August 2nd, 2012, 05:59 PM
clivew clivew is offline
Contributing User
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2006
Location: Carlsbad, CA
Posts: 2,045 clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Week 6 Days 2 h 37 m
Reputation Power: 382
To follow up:
I posted my suggestions before reading maljumbo's latest posts.

maljumbo's suggestion of the nested try...finally blocks and creating the TStringLists before each try is the best.
However, my suggestion of initializing the TStringList variables to nil first and then
creating all but the first one inside the try...finally block is a technique often used
when creating a large number of objects (as you are) to avoid having
try...finally blocks nested six or seven deep.

If you create each individual TStringList outside its own try...finally block you do
not need to initialize it to nil first.

Last edited by clivew : August 2nd, 2012 at 06:01 PM. Reason: Added the final paragraph

Reply With Quote
  #12  
Old August 2nd, 2012, 06:05 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Quote:
Originally Posted by clivew
Yes. Ignore inline for now. There are more important things to get your mind around first.

Exceptions - this is more important!
Do learn about them.
You create your own with code such as this:
Code:
  raise Exception.Create('my error message here');

There are, of course, other variations; but this is the simplest.

The big difference between this and your exit statements is this:
Exit; simply exits the current procedure and the calling procedure will try to continue
from the point at which the the procedure that just exited returns.
An Exception raised will just keep walking up the call stack (without trying to run any intervening code)
until it finds the first Except clause. If it does not find one of yours, then it will
eventually hit the default except clause that Delphi has wrapped round your entire application.

Hope this clarifies a little.

Clive


Thanks, Clive. I think I understand. But it appears to me that raising an exception the way you demonstrated will help the developer only, whereas a ShowMessage or MessageDlg needs to be used if I want to give my GUI to an uninitiated user. But maybe there is a way?

Reply With Quote
  #13  
Old August 2nd, 2012, 06:52 PM
clivew clivew is offline
Contributing User
Dev Shed Regular (2000 - 2499 posts)
 
Join Date: Jan 2006
Location: Carlsbad, CA
Posts: 2,045 clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level)clivew User rank is Major (30000 - 40000 Reputation Level) 
Time spent in forums: 1 Week 6 Days 2 h 37 m
Reputation Power: 382
Quote:
Thanks, Clive. I think I understand. But it appears to me that raising an exception the way you demonstrated will help the developer only, whereas a ShowMessage or MessageDlg needs to be used if I want to give my GUI to an uninitiated user. But maybe there is a way?

Yes.
When you get to the except block you do whatever cleanup is needed and then use messageDlg or showmessage, if appropriate, to inform the user.
Delphi's default except clause does that if you do nothing in between.

To use the example already given:
Code:
function DivideNums(A, B: Integer): Double;
begin
   try
      Result := A/B;
    except
       on EZeroDivide do
          MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
    end;
end;


Now adjust that.
Code:
function DivideNums(A, B: Integer): Double;
begin
   Result := A/B;
end;
function dothis(A, B: Integer): Double;
begin
   result := DivideNums(A, B);
   ShowMessage('Division succeeded');
end;

procedure DoIt(A, B: Integer): Double;
var
  myVal: Double;
begin
   try
     myVal := doThis(A,B);
     showMessage(intToStr(trunc(myVal));
   except
      // catch something we know might happen
      on EZeroDivide do
         MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
      // Deal with the unknown mishap 
      on E: Exception do
         MessageDlg('Something unexpected happened. Here is all I know '
         +E.message,mtError, [mbOK], 0) ;
    end;  //except
end;


I hope this illustrates a couple of things.
1.
If B was zero then an EZeroDivide exception will be raised by Delphi.
Because of that the code will jump immediately to the except clause in
DoIt.
a. The line ShowMessage('Division succeeded'); will not execute.
b. You do not have to worry about anything invalid being returned into myVal
c. showMessage(intToStr(trunc(myVal)); will not execute.

2.
If EZeroDivide is found then you know what you want to do.
If it drops into the catch all Exception then you can show a custom message and add on the
message that the unexpected exception returned that the user can tell the developer
for debugging.

Clive

Reply With Quote
  #14  
Old August 2nd, 2012, 07:17 PM
majlumbo majlumbo is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2008
Posts: 254 majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level)majlumbo User rank is Lance Corporal (50 - 100 Reputation Level) 
Time spent in forums: 2 Days 23 h 55 m 14 sec
Reputation Power: 5
Quote:
Originally Posted by llaama2012
(By the way, it is "if CompareValue(ResSS, Min_ResSS) = 0 then ...", right, and not "if CompareValue(ResSS = Min_ResSS) = 0 then ..."?)


That is correct, copy and paste will get you every time....

I edited my post to reflect this...

Last edited by majlumbo : August 2nd, 2012 at 07:20 PM.

Reply With Quote
  #15  
Old August 3rd, 2012, 12:32 PM
llaama2012 llaama2012 is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2012
Posts: 23 llaama2012 User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 5 h 27 m 11 sec
Reputation Power: 0
Quote:
Originally Posted by clivew
Yes.
When you get to the except block you do whatever cleanup is needed and then use messageDlg or showmessage, if appropriate, to inform the user.
Delphi's default except clause does that if you do nothing in between.

To use the example already given:
Code:
function DivideNums(A, B: Integer): Double;
begin
   try
      Result := A/B;
    except
       on EZeroDivide do
          MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
    end;
end;


Now adjust that.
Code:
function DivideNums(A, B: Integer): Double;
begin
   Result := A/B;
end;
function dothis(A, B: Integer): Double;
begin
   result := DivideNums(A, B);
   ShowMessage('Division succeeded');
end;

procedure DoIt(A, B: Integer): Double;
var
  myVal: Double;
begin
   try
     myVal := doThis(A,B);
     showMessage(intToStr(trunc(myVal));
   except
      // catch something we know might happen
      on EZeroDivide do
         MessageDlg('Can not divide by zero!',mtError, [mbOK], 0) ;
      // Deal with the unknown mishap 
      on E: Exception do
         MessageDlg('Something unexpected happened. Here is all I know '
         +E.message,mtError, [mbOK], 0) ;
    end;  //except
end;


I hope this illustrates a couple of things.
1.
If B was zero then an EZeroDivide exception will be raised by Delphi.
Because of that the code will jump immediately to the except clause in
DoIt.
a. The line ShowMessage('Division succeeded'); will not execute.
b. You do not have to worry about anything invalid being returned into myVal
c. showMessage(intToStr(trunc(myVal)); will not execute.

2.
If EZeroDivide is found then you know what you want to do.
If it drops into the catch all Exception then you can show a custom message and add on the
message that the unexpected exception returned that the user can tell the developer
for debugging.

Clive


Hmmm, so you raise the exceptions in the procedure rather than in the functions? Is that why the program jumps to the next command in the procedure upon Delphi finding an exception (such as dividing by zero), but now a custom message is displayed rather than the default message by Delphi? Is that the idea? Boy, it is going to take some mental gymnastics for me to come up with code like this! It seems to come so naturally to you guys.

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming Languages - MoreDelphi Programming > Invalid pointer problem

Developer Shed Advertisers and Affiliates



Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap