Błąd dostępu

0

Witam, mam taki oto kod:

type
  TFieldType = 0..1;
  TField = array[0..101,0..101] of TFieldType;

[...]

TLife = class
  private
    FField : TField;

[...]

constructor TLife.Create;
var
  i, j : integer;
  m : TField;
begin
  inherited;
  for i:=0 to 101 do for j:=0 to 101 do m[i,j] := 0;
  m[11,10] := 1;
  m[12,11] := 1;
  m[10,12] := 1;
  m[11,12] := 1;
  m[12,12] := 1;
  FField := m;
end;

I przy uruchamianiu wywala mi się błąd:
[...] EAccessViolation with message '[...] write of address 00000004' [...]
w linijce:
FField := m;

Zupełnie nie rozumiem o co kompilatorowi może chodzić. Domyślam się tylko, że jest to związane z jedynie teoretyczną zgodnością między rodzajami zmiennych (być może w praktyce zmienna FField jest jakimś cudem innego rodzaju zmienną niż m...).
Czy ktoś orientuje się czym może być wywołany błąd?

0

przejedź po kodzie linijka po linijce debugerem, zobacz jaki jest stan zmiennych.
któraś ze zmiennych, do których się odwołujesz, jest null, lub wychodzisz poza zakres tablicy. akurat kawałek wklejonego kodu wygląda prawidłowo.

0

Na pewno nie wychodzę poza zakres, sprawdzałem to (to było moje główne podejrzenie). No ale ok, przelecę wszystko debugerem i się okaże.

0

Błąd powoduje inny fragment kodu, ten jest poprawny. Sprawdź jeszcze czy nie ma jakiegoś konfliktu z typem TField zdefiniowanym w db.

0

Niestety, szukałem i nic złego nie znalazłem ;(. Może ktoś by się dopatrzył, oto kod:

unit silnik;

interface

type
  TFieldType = 0..1;
  TField = array[0..101,0..101] of TFieldType; // mapa zaczyna sie od 1, a konczy na 100. Wiekszy obszar zostal wprowadzony dla poprawnego dzialania programu
  TCellNeighbours = record
    map : array [1..3, 1..3] of TFieldType;
    count : integer;
  end;

  TLife = class
  private
    FField : TField;
    function CheckCell(CellX, CellY : integer; output : TCellNeighbours) : boolean;
    function GetField : TField;
  public
    property Field : TField read GetField;
    procedure CreateMap(generates : integer);
    constructor Create;//(FirstGenerate : TField);
  end;



implementation



function TLife.CheckCell(CellX, CellY : integer; output : TCellNeighbours) : boolean;
var
  i, j: integer;
begin
  result := false;
  for i:=1 to 3 do for j:=1 to 3 do output.map[i,j] := 0;

  if FField[CellX, CellY] = 0 then
  begin
    for j:=0 to 2 do
    begin
      for i:=0 to 2 do
      begin
        if FField[CellX+i-1, CellY+j-1] = 1 then
        begin
          inc(result);
          output.map[i+1, j+1] := 1;
        end;
      end;
    end;
    result := true;
  end;
end;



procedure TLife.CreateMap(generates : integer);
var
  gen, i, j : integer;
  output : TCellNeighbours;
  map2 : TField;
begin
  for i:=0 to 101 do for j:=0 to 101 do map2[i,j] := 0;

  for gen:=1 to generates do
  begin
    for j:=1 to 100 do
    begin
      for i:=1 to 100 do
      begin
        checkCell(i,j,output);
        if (FField[i,j]=0) and (output.count = 2) then map2[i,j] := 1
        else if (FField[i,j]=1) and (output.count <> 2) then map2[i,j] := 0;
      end;
    end;
    FField := map2;
  end;
end;



function TLife.GetField : TField;
begin
  result := FField;
end;


constructor TLife.Create;//FirstGenerate : TField);
var
  i, j : integer;
  m : TField;
begin
  inherited;
  for i:=0 to 101 do for j:=0 to 101 do m[i,j] := 0;
  m[11,10] := 1;
  m[12,11] := 1;
  m[10,12] := 1;
  m[11,12] := 1;
  m[12,12] := 1;
  FField := m;
  //FField := FirstGenerate;
end;

end.

Opis funkcji, procedur i konstruktora:
CheckCell - zwraca ilość i położenie komórek sąsiadujących względem podanej komórki;
GetField - użyta do właściwości, podaje aktualną mapę;
CreateMap - tworzy x-te pokolenie z mapie FField i zapisuje je do niej;
Create - tworzy standardową mapę i zapisuje ją do FField.

Na marginesie podam, że chodzi o grę w życie. Kompletnie nie wiem co może być przyczyną...

0

Pokaż przykład jak wywołujesz funkcje;

Poza tym, masz źle zdefiniowany wynik funkcji:

[Pascal Hint] Unit1.pas(61): H2077 Wartość przydzielona do 'TLife.CheckCell' nigdy nie została użyta

function TLife.CheckCell(CellX, CellY : integer; output : TCellNeighbours) : boolean;
var
  i, j: integer;
begin
  result := false;
  for i:=1 to 3 do for j:=1 to 3 do output.map[i,j] := 0;

  if FField[CellX, CellY] = 0 then
  begin
    for j:=0 to 2 do
    begin
      for i:=0 to 2 do
      begin
        if FField[CellX+i-1, CellY+j-1] = 1 then
        begin
          inc(result);  ///<<<<<<<<<<--------------------
          output.map[i+1, j+1] := 1;
        end;
      end;
    end;
    result := true;
  end;
end;
0

Funkcji (silnika) nie używam praktycznie w ogóle. Znaczy używam, ale nie wprowadzam żadnych własnych danych. Jest po prostu:

var
  s : TLife;
begin
  s.Create;
end;

Tak więc błąd jest w silniku. Co do znalezionego przez Ciebie błędu... Fakt, to pozostałość ze starej wersji funkcji. Poprawnie powinno być:

inc(output.count);

Wiem, że błąd powoduje konstruktor lub zmienne. Przeanalizowałem dokładnie cały Create i nie dopatrzyłem się żadnych błędów. Zmienne... też raczej w porządku. O co kompilatorowi właściwie chodzi? Czy jest jakaś wartość w adresie 00000004 (patrz post 1)?

0

Masz błąd dokładnie w tej linii, przy przypisywaniu:

FField := m;

Czyli już wiesz, że tak nie można.
Jak można ? Nie wiem

Poza tym Twoja funkcja

function TLife.CheckCell(CellX, CellY : integer; output : TCellNeighbours) : boolean;

jest używana jako procedura.

0

Dzięki, poprawiłem funkcję na procedurę.
Właśnie próbuję ustalić co może być przyczyną, że "FField := m;" nie działa. Pisze, że błąd dostępu... Dlaczego? za zakres nie wychodzę, bo obie zmienne mają ten sam typ... Chyba będę musiał porzucić projekt ;/.

0

Odwołujesz się (przypisujesz) do FField, które nie jest widoczne z poziomu Constructora.

0

Próbowałem "TLife.FField", ale pisze "Method identifier expected"... Dawałem też FField do zmiennych publicznych, z tym samym skutkiem. Istnieje możliwość przypisania w konstruktorze wartości do jakiejkolwiek zmiennej klasy?

1 użytkowników online, w tym zalogowanych: 0, gości: 1