Access Violation error....

0

Witam. Mam problem z modyfikacją zmiennych klasy.

mam taką oto klasę :

type

TTab = array of array of array of double;
TStr = string;
TWczytaj = class

public
Date : Tstr ;
Name : Tstr ;
TabSkatBRDF : array of array of array of double;
function Sprawdz(Naglowek: string; Open : TOpenDialog) : integer ;
end;

a tutaj kod programu głównego a właściwie jedną z jego procedur

procedure TFrmMain.Otworz1Click(Sender: TObject);
var
Wczytaj : TWczytaj;
s :string;
TF : TextFile;
begin
s:= '#Data Generated By Imaging Sphere Version: 1.4.34.0';
if Wczytaj.Sprawdz(s , OpnBRDF1)=1 then
    begin
    Memo1.Lines.Add('dobrze!!!');
    AssignFile(TF,OpnBRDF1.FileName);
    Reset(TF);
    Readln(TF , s);
    Readln(TF , s);
    Wczytaj.Date := s;
    Readln(TF , s);
    Wczytaj.Name := s;
    end else
    MessageBox(Handle, 'Nieodpowieni format pliku!', 'WRONG!', MB_OK or MB_ICONERROR);
end; 

w linii "Wczytaj.Date :=s" wyskakuje błąd -
"Project BRDF.exe raised exception class EAccessViolation with message 'Access violation at address 40006928 in module 'rtl70.bpl'. Write of address 00000004'. Process stopped. Use Step or Run to continue."

Bardzo proszę o pomoc.

0
kozi555 napisał(a):

Bardzo proszę o pomoc.

Pomóż sam sobie:
1.Zadając pytanie?
2.Używając debuggera?
3.Dając lepszą nazwę wątku?
4.Wszystkie odpowiedzi są poprawne?

0
  1. Pytania o banalne podstawy zdajemy w dziale Newbie
  2. Koniecznie tagujemy wątki nazwą środowiska / języka.
  3. Najpierw zanim zaczniemy coś pisac opartego o klasy należy okiełznać podstawy języka z kursów.
  4. Formatujemy kod prawidłowo, a nie wcięcia "z d**y".
  5. Przede wszystkim jakbyś poczytał kiedy występuje bład AV to byś wszystko wiedział.
  6. Nie widzę tworzenia Wczytaj, do którego się później odwołujesz.
0

Jeżeli masz problem z klasami, to może spróbuj najpierw z rekordami.

1

To, co chcesz zrobić, w taki sposób przeszłoby przy advanced records.
Klasę należy stworzyć (wywołać konstruktor).

0

Dziekuje. Rozwiązało to mój problem niemniej jednak pojawił się następny.. chciałbym aby obiekt Wczytaj klasy TWczytaj pobierał sobie jakies tam dane w jednej procedurze a w drugiej procedurze czy też funkcji te dane byłyby dostępne. Należy chyba przekazać obiekt Wczytaj jako parametr do procedury/funkcji ? Jeśli tak to prosiłbym o pomoc jak to zrobić. Pozdrawiam.

0

Oczywiście jak to zwykle w tym dziale przed analizą zamieszczonego kodu trzeba go koniecznie sformatować...:

type
  TTab = array of array of array of double;
  TStr = string;

  TWczytaj = class(TObject)
  public
    Date: TStr;
    Name: TStr;
    TabSkatBRDF: array of array of array of double;

    function Sprawdz(Naglowek: string; Open: TOpenDialog): Integer;
  end;

procedure TFrmMain.Otworz1Click(Sender: TObject);
var
  Wczytaj: TWczytaj;
  S : String;
  TF: TextFile;
begin
  S := '#Data Generated By Imaging Sphere Version: 1.4.34.0';

  if Wczytaj.Sprawdz(s, OpnBRDF1) = 1 then
    begin
      Memo1.Lines.Add('dobrze!!!');
      AssignFile(TF, OpnBRDF1.FileName);
      Reset(TF);
      Readln(TF, s);
      Readln(TF, s);
      Wczytaj.Date := s;
      Readln(TF, s);
      Wczytaj.Name := s;
    end
  else
    MessageBox(Handle, 'Nieodpowieni format pliku!', 'WRONG!', MB_OK or MB_ICONERROR);
end;

Teraz cokolwiek przynajmniej widać...

Po pierwsze - zadeklarowany masz typ TTab, z którego w ogóle nie korzystasz, a pole klasy TabSkatBRDF jest dokładnie tego typu - pewnie zapomniałeś podmienić nazwę typu;

Po drugie - deklarujesz alias TStr = String - jest to niepotrzebne; Oczywiście można to wykorzystywać, ale aliasy służą jedynie do zwiększenia czytelności kodu (choć TStr jest mniej intuicyjne niż wszystkim znany i szanowany String);

Po trzecie - zapewne nie przeczytałeś żadnego kursu na temat programowania obiektowego dlatego nie wiesz, że obiekt trzeba utworzyć w pamięci żeby można było z niego korzystać, analogicznie po zakończeniu pracy z danym obiektem trzeba go z pamięci usunąć - służą do tego konstruktor i destruktor; Ty nie masz w ogóle zadeklarowanego ani konstruktora, ani dekstruktora (oczywiście można wykorzystać odziedziczony konstruktor / destruktor i nie deklarować własnych, ale za ich pomocą obiekt i tak trzeba utworzyć i zwolnić z pamięci);

Po czwarte - w deklaracji klasy podana jest deklaracja metody Sprawdz, jednak nie podałeś jej definicji - skąd mamy wiedzieć, że to właśnie w ciele tej metody nie jest powodowany wyjątek...? Zamieść jego definicję jeśli dalej nie możesz znaleźć błędu;

Po piąte - wykorzystujesz wcześniej wspomniany obiekt bez jego utworzenia w pamięci, więc w tym momencie na pewno otrzymasz Access Violation; Zasadę korzystania z obiektów musisz poznać - przeczytaj podstawy programowania obiektowego (OOP) z linku, który Ci wcześniej podałem a będziesz wiedział w czym tkwi błąd;

Po szóste - wykorzystujesz przekazywany przez argument metody Sprawdz obiekt klasy TOpenDialog - dziwna jest taka konstrukcja; Ja osobiście wolę nie kłaść tego komponentu na formularz - zadeklarować sobie lokalną zmienną i ręcznie ją utworzyć, ustawić wartości interesującym mnie polom i wywołać metodę Execute, sprawdzić jej rezultat i pobrać ścieżkę z obiektu; Jeśli musisz wykorzystać ten dialog w kilku miejscach w programie to polecam napisać sobie prostą funkcję, w której będziesz wykorzystywał taki obiekt i zwracał ścieżkę, a w argumentach podasz informacje dla pól obiektu; Ale to wykonasz dopiero jak nauczysz się podstaw obiektówki;

Po siódme - wykorzystujesz zmienną plikową jednak konstrukcja jest nienajlepsza - jeżeli wykorzystujesz pliki to pakuj je do bloku try .. finally .. end - jest bezpieczniej; To samo tyczy się tworzenia obiektów w danej procedurze / funkcji / metodzie jeśli są one lokalne - warto stosować ten blok oraz w niektórych przypadkach try .. except .. end dla przechwytywania wyjątków; Dzięki temu zauważyłbyś, że wykorzystujesz tą zmienną, otwierasz plik do odczytu, czytasz dwie linie i nie zamykasz pliku (procedura CloseFile), stąd powodujesz wycieki pamięci; Prawidłowy blok operacji na pliku powinien wyglądać tak:

AssignFile(TF, OpnBRDF1.FileName);

try
  Reset(TF);
  Readln(TF, s);
  Readln(TF, s);
  Wczytaj.Date := s;
  Readln(TF, s);
  Wczytaj.Name := s;
finally
  CloseFile(TF)
end;

Po ósme - w ww. bloku wykonujesz pod rząd dwa razy wczytanie bieżącej linii z pliku, stąd pierwszej linii nigdy nie będziesz mógł wykorzystać, bo do pola Wczytaj.Date zawsze trafi druga linia, a do pola Wczytaj.Name zawsze trzecia;

Tak więc podsumowując najpierw przejrzyj temat programowania obiektowego (głównie o konstruktorach i destruktorach), poczytaj o dynamicznym tworzeniu obiektów (przyda się do tworzenia procedury / funkcji wywołującej okno dialogowe - ale to jako ciekawostkę), o bloku try .. finally .. end i try .. except .. end i o procedurze CloseFile; Potem zabierz się za kodzenie, a jeśli dalej nie będziesz mógł odnaleźć błędów to poczytaj także o debugowaniu aplikacji w Delphi - to musisz się nauczyć żeby usamodzielnić się trochę;

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