全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1395
推到 Plurk!
推到 Facebook!

function 傳回的值會出現 Access violation

尚未結案
ayachan
一般會員


發表:7
回覆:8
積分:8
註冊:2004-04-03

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-02-24 00:14:23 IP:211.20.xxx.xxx 未訂閱
例:
procedure DoProcess;
var
  vNumber: double;
begin
  vNumber:=Calculate;
  (下面還有計算) 
end;    function  Calculate: double;
var
  vResult: double
begin
  (當然實際裡面是很多計算,計算出 vResult)
  Result:=vResult;
end;
類似這樣的程式, 會在「vNumber:=Calculate;」這一行出現 Access violation。 而這一段程式是在別的系統裡執行無誤的。 如果只執行 Calculate; 不會錯誤。 Calculate 裡的 vResult 值是 double,沒有任何錯誤。 只要一執行 vNumber:=Calculate;,用 Watch Window 來看 vNumber 的值, 會發現從 0 變成 -NAN,然後就 Access violation 了。 請問為什麼會發生這個狀況,要怎樣解決呢? 先謝謝熱心回答的前輩了。
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-02-24 06:43:24 IP:203.14.xxx.xxx 未訂閱
引言: 如果只執行 Calculate; 不會錯誤。
如果在Delphi的设置中选择了优化代码, Delphi在Compile时会Ignore这行代码, 因为它不发挥任何任何作用. 即使Calculate存在runtime錯誤也不会表现出来.
引言: 會在「vNumber:=Calculate;」這一行出現 Access violation。
錯誤很可能发生在 Calculate 里. 保留 vNumber:=Calculate, 然后在 Result:=vResult 处加个break point, 试试能否运行到这个reak point. 如果不能, 可以确定Calculate有问题. 如果能, ..... 思考中 ......
yorkland
高階會員


發表:2
回覆:138
積分:108
註冊:2004-12-17

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-02-24 10:59:01 IP:220.130.xxx.xxx 未訂閱
function  Calculate: double;
var
  vResult: double  // 這是Local變數
begin
  (當然實際裡面是很多計算,計算出 vResult)
  Result:=vResult;  // 當回傳資料時, vResult已經被Free掉了。
end;    建議寫法..
procedure DoProcess;
var
  vNumber: double;
begin
  Calculate(vNumber);
  (下面還有計算) 
end;    function Calculate(var vResult: Double): Boolean;
begin
  // 因為宣告成var的傳址方式, 在子程式段可以直接改寫變數的值。
  // 善用var的方式, 把變數的宣告放在上層, 可避開不知何時Free的問題。
end;
mustapha.wang
資深會員


發表:89
回覆:409
積分:274
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-02-24 12:08:31 IP:218.80.xxx.xxx 未訂閱
trace看看,错误可能在Calculate内部。 yorkland的原因说法是错误的。     久病成良医--多试 千人之诺诺,不如一士之谔谔--兼听 發表人 - mustapha.wang 於 2005/02/24 12:11:56
------
江上何人初见月,江月何年初照人
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-02-24 12:47:55 IP:203.14.xxx.xxx 未訂閱
double和integer, single, currency等一样是进行值传输, 而非地址传输. 即使Local变数从Stack中清除掉也不会影响function的返回值.
ayachan
一般會員


發表:7
回覆:8
積分:8
註冊:2004-04-03

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-02-24 13:20:13 IP:61.220.xxx.xxx 未訂閱
Calculate 裡是有計算出正確的值的, 以我測試用的範例輸入,計算出來的值是 21.86。    把 function 改成用 var 的方式也有試過, 可是 vNumber 只要一接到計算出來的結果,就會 Access violation。
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-02-24 17:51:42 IP:220.244.xxx.xxx 未訂閱
最好能把代码发上来大家看看.
ayachan
一般會員


發表:7
回覆:8
積分:8
註冊:2004-04-03

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-02-24 21:42:49 IP:211.20.xxx.xxx 未訂閱
function CalFactor:double;
var
  CashRate: double;     
  DORate: double;
  FixFactor,varValue: double;  
  varDx: double;
  i,j:integer;
  varDxArray:array[0..110] of double;
  varNxArray:array[0..110] of double;
  varD,varLD: double;
begin
  FillChar(varDxArray,SizeOf(varDxArray),#0);
  FillChar(varNxArray,SizeOf(varNxArray),#0);
  doRate:= MRate/100;
  CashRate:= 1/(1 DoRate);
  varD:=1-(CashRate);
  for i:=Age to High(Lx[0]) do
    begin
      varValue:= Power(CashRate,i);
      varDxArray[i]:=varValue*Lx[Sex,i];
    end;
  for i:=Age to High(Lx[0]) do
    begin
      varDx:=0;
      for j:=i to High(Lx[0]) do
        varDx:=varDx varDxArray[j];
      varNxArray[i]:=varDx;
    end;
  varLD:= POWER(CashRate,PromiseYear);
  FixAnnFactor:=varNxArray[RetireAge PromiseYear]/varDxArray[RetireAge] (1-varLD)/varD;
Result:=FixFactor;
end;
Age、Sex、PromiseYear 等都是全域變數 Lx 是 array[0..1,0..110] of double
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-02-25 06:36:21 IP:203.14.xxx.xxx 未訂閱
如果trace这个函数, Access violation发生在哪一行? 你所发的代码没有明显的问题, 唯一的疑问是你能保证 RetireAge PromiseYear <= 110 吗? 另外, 这还是一个simplified version, 是吗?
ayachan
一般會員


發表:7
回覆:8
積分:8
註冊:2004-04-03

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-02-25 09:14:07 IP:61.220.xxx.xxx 未訂閱
Age 的最小值為 0;最大值只能到 60。 而 RrtireAge 的最小值會等於 Age;最大值只能到 70。 PromiseYear 只能為 10、15、20 三個值。 所以 RetireAge PromiseYear 一定會小於 110。 這一段完全是原 function 了,沒有再刪任何的 code。
yorkland
高階會員


發表:2
回覆:138
積分:108
註冊:2004-12-17

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-02-25 09:21:55 IP:220.130.xxx.xxx 未訂閱
可以請你再確認下列二個值 其中varDxArray[RetireAge]及varD 都是當分母, 分母不得為零, 但在程式碼中看不到這二個值的定義。 也許問題是發生在這個值為"零"上頭。 FixAnnFactor:=varNxArray[RetireAge PromiseYear]/varDxArray[RetireAge] (1-varLD)/varD;
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-02-25 09:49:54 IP:203.14.xxx.xxx 未訂閱
引言: .... Result:=FixFactor; .... 這一段完全是原 function 了,沒有再刪任何的 code。
1. 没见到给 FixFactor 赋值啊? 2. 能回答一下: 如果trace这个函数, Access violation发生在哪一行? 3. 请将call CalFactor处前后几行代码也post出来, 这样整个Scenario就完整了. 發表人 - yyu10 於 2005/02/25 11:08:10
ayachan
一般會員


發表:7
回覆:8
積分:8
註冊:2004-04-03

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-02-26 12:31:37 IP:211.20.xxx.xxx 未訂閱
FixFactor 是倒數第三行那邊給值的,貼上來時不小心打成 FixAnnFactor,已修正。    在 CalFactor 裡,所有的數值(包括 FixFactor 的值)都可以正常運算出來,不會有任何的錯誤。    
  Rate:=0.02;
  AccountTValue:=inValue;
  for i:=0 to (RetireAge-Age-1) do     // 以複利計算
  begin
    AccountTValue:=(AccountTValue-1500);  
    AccountTValue:=(AccountTValue*Rate);
  end;      //===原先在另一個程式可以執行不會出錯,可是在這就會Access Violation
  AnnVal:=CalFactor;    // 錯在這一行,
                        // 一把 CalFactor 的值 Assign 給 AnnVal,
                        // AnnVal 就會變成-NAN,然後就 Access Violation 了。
  tmpAnnVal:=AnnVal;
  AnnVal:=AccountTValue/AnnVal;
  //=========================================================      if ((AnnVal>1200000)or(AnnVal<10000)) then
  begin
    if (AnnVal>1200000) then
      AnnVal:=1200000
    else
      AnnVal:=0;
    SValue:=tmpAnnVal;       // 另記錄下來顯示用
  end
  else
    AnnVal=PayBack;      for i:=(RetireAge-Age-1) to (110-Age) do
    tmpAry[i]:=AnnVal;               // 顯示用
yyu10
中階會員


發表:9
回覆:99
積分:96
註冊:2005-02-18

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-02-27 08:11:14 IP:220.244.xxx.xxx 未訂閱
程式没有明显的错误. 这个问题有趣的地方在于, 程式中没有用到通常可能引起 A.V. 的东西, 比如 poiter, dynamic array , object, etc. 另外一种可能引起 A.V. 的原因是 stack corrupted. Stack pointer 和 base pointer 在 function call 后回不到该回的位置, 也会引起 A.V. 不过直接测试很麻烦, 需要在 CPU View 里观察 stack 在 call 前后的变化, 一两句话说不清楚. 还是先试试比较笨拙的办法吧, 下面是一个比较系统的测试计划, 一步一步的做. Step 1: //AnnVal:=CalFactor; AnnVal:= 1234; Step 2: 在 CalFactor 之前加个新function. function FakeCalFactor: double; begin Result := 1234; end; 然后, //AnnVal:=CalFactor; AnnVal:= FakeCalFactor; **************************************** 1和2是用来确认DoProcess没有问题. **************************************** Step 3: 将 CalFactor 中Var部分Copy到 FakeCalFacotr, 测试一次. Step 4: 将 CalFactor 中的代码逐行Copy到 FakeCalFacotr的 Result := 1234 之前, 每Copy一行测试一次, 直到出现A.V.时停下来. Loop作为一个整体看待. **************************************** 在做所有测试之前, 请先检查一下Compiler的选项 Project -> Options -> Compiler: Code Generation: Optimazation (Unchecked) Aligned Record Fields (Checked) Stack frames (Checked) Pentium-safe FDIV (Unchecked) Runtime errors: All Checked Debugging: All Checked except "Definitions Only". 然后 Build project(NOT Compile project). **************************************** _________________________ Programming is a passion 發表人 - yyu10 於 2005/02/27 11:26:53
StrongLemon
高階會員


發表:10
回覆:166
積分:105
註冊:2004-04-18

發送簡訊給我
#15 引用回覆 回覆 發表時間:2005-02-28 03:34:15 IP:203.67.xxx.xxx 未訂閱
您好:我修正過後如下,試試看哪裡會出問題    
function TForm1.CalFactor:double;
var
  CashRate: double;
  DORate: double;
  FixFactor,varValue: double;
  varDx: double;
  i,j:integer;
  varDxArray:array[0..110] of double;
  varNxArray:array[0..110] of double;
  varD,varLD: double;
begin
  try
    FillChar(varDxArray,SizeOf(varDxArray),#0);
    FillChar(varNxArray,SizeOf(varNxArray),#0);
    doRate:= MRate/100;
    CashRate:= 1/(1 DoRate);
    varD:=1-(CashRate);
    if (Sex in [0,1]) then
    begin
      for i:=Age to High(Lx[Sex]) do
        begin
          varValue:= Power(CashRate,i);
          varDxArray[i]:=varValue*Lx[Sex,i];
        end;
      for i:=Age to High(Lx[Sex]) do
        begin
          varDx:=0;
          for j:=i to High(Lx[Sex]) do
            varDx:=varDx varDxArray[j];
          varNxArray[i]:=varDx;
        end;
    end
    else
      Raise Exception.Create('Sex is error');
    varLD:= POWER(CashRate,PromiseYear);
    if ((RetireAge>=0) and (RetireAge<=100)) and
       (varDxArray[RetireAge]>0) and
       (varD>0) then
    begin
      if ((RetireAge PromiseYear)<=High(varNxArray)) and
         (RetireAge<=High(varDxArray)) and
         ((RetireAge PromiseYear)>=0) and
         (RetireAge>=0) then
        FixFactor:=varNxArray[RetireAge PromiseYear]/varDxArray[RetireAge] (1-varLD)/varD
      else
        Raise Exception.Create('(RetireAge PromiseYear)>High(varNxArray) or ' 
                               'RetireAge>High(varDxArray) ' 
                               '(RetireAge PromiseYear)<0' 
                               'RetireAge<0 and RetireAge>110 error' );
    end
    else
      FixFactor:=NAN;
    Result:=FixFactor;
  except
    On E:Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;
mustapha.wang
資深會員


發表:89
回覆:409
積分:274
註冊:2002-03-13

發送簡訊給我
#16 引用回覆 回覆 發表時間:2005-03-01 09:14:45 IP:218.80.xxx.xxx 未訂閱
你的代码编译不过,MRate等没有定义,能不能贴点完整的?     久病成良医--多试 千人之诺诺,不如一士之谔谔--兼听
------
江上何人初见月,江月何年初照人
系統時間:2024-05-19 9:14:36
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!