【问题标题】:Why is "result := char variable" getting me access violation? [closed]为什么“结果:= char 变量”让我访问冲突? [关闭]
【发布时间】:2021-03-06 14:05:55
【问题描述】:

我创建了一个函数,它的 Char 由一个名为 fsinal 的变量表示:

type
  TCalculo = class(TObject)
  private
    fnumero1 : integer;
    fnumero2 : integer;
    fsinal   : char;
  public

然后我创建了一个方法来获取这个Char

function getSinal   : char;
    
function TCalculo.getSinal: char;
begin
  result := fsinal;
end;

每当我朗读我的程序并按下任何按钮时,我都会收到错误消息

在地址 005FD704 的访问冲突,读取地址 0000000C:

我做错了什么?

完整代码:

https://github.com/murillojndem/Calculadora/blob/master/Unit1.pas

【问题讨论】:

  • TCalculo 是一个,为了使用它(class 变量、方法和属性除外),您首先需要创建一个实例(=object)其中。我敢打赌你忘记了。 (calculo := TCalculo.Create 创建该类的一个对象并将指向它的指针分配给calculo 变量,然后您可以在此行之后 使用它。在此行之前,calculo 是一个@ 987654337@指针(如果是全局变量或类成员)或“随机垃圾”指针(如果是局部变量)。)
  • 此处不接受异地代码链接。所有相关内容都需要以minimal reproducible example 的形式出现在问题本身中。如果您花一些时间在tour 和阅读help center 页面以了解该网站的工作原理,然后再开始发布,您会发现您在这里的体验会好很多。
  • 我应该在哪里添加“calculo := TCalculo.create”?我尝试添加的任何地方似乎都会返回错误。
  • 您需要在使用它之前创建对象。然后,您需要在 使用完之后释放它。这是普遍的真理。雷米在他的回答中给了你两个非常明确的例子。

标签: function variables delphi get char


【解决方案1】:

地址$00000000 附近的访问冲突错误通常意味着您正在通过nil 指针访问内存。

在这种情况下,地址 $0000000C 是地址 $00000000 的 12 个字节。 TCalculo.getSinal() 方法正在访问fsinal 成员,该成员距离TCalculo 类的开头有12 个字节的偏移量(偏移量0 是指向TCalculo 的vtable 的隐藏指针,偏移量4 是@ 987654330@成员,偏移8为fnumero2成员,最后偏移12为fsinal成员)。

result := fsinal;result := Self.fsinal;一样,编译器将fsinal的偏移量(12)加到Self指向的地址上,然后解引用得到的地址来访问@的值987654337@。在您的情况下,您通过指向TCalculo 对象的nil 指针调用TCalculo.getSinal(),因此该方法的Self 指针为nil (0),从而取消引用fsinal 的地址(0+12 ) 导致 AV 错误。

在您的TForm 代码中,您的所有TButton.OnClick 处理程序都在一个从未被初始化为指向有效TCalculo 对象的全局calculo 变量上调用getSinal()。由于calculo 变量是在全局内存中声明的,所以在程序启动时默认初始化为nil

type
  TCalculo = class(TObject)
    ...
  end;

var
  Form1  : TForm1;
  calculo: TCalculo; // <-- initialized to nil here!

...

procedure TForm1.Button0Click(Sender: TObject);
begin
  if calculo.getSinal = 'a' then // <-- calculo is still nil here!
  ...
end;

... and so on...

您需要在TForm.OnCreate 事件中添加对TCalculo.Create() 的调用(反之,在TForm.OnDestroy 事件中添加Free 对象),例如:

procedure TForm1.FormCreate(Sender: TObject);
begin
  calculo := TCalculo.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  calculo.Free;
end;

或者,使用单位的 initialization 部分(反之,finalization 部分),例如:

implementation

...

initialization
  calculo := TCalculo.Create;
finalization
  calculo.Free;

end.

【讨论】:

  • 感谢您的详细回复,非常感谢。但是我在这里做了同样的事情,没有问题,为什么? github.com/murillojndem/Calculadora-de-notas-N2-OOP-/blob/…
  • @MurilloJorge:不,你显然在第 48 行有 calculo := TCalcula.create;
  • 这是内存泄漏。在第一次单击Button1 后,calculo 对象永远不会被Free'd。并且每次后续点击都会创建一个 new TCalcula 对象,而没有 Free'ing 前一个对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-23
  • 1970-01-01
  • 1970-01-01
  • 2019-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多