Zmienna nie została zainicjowana (w czym problem)

0

Witam

Poniższy przypadek z mojego punktu widzenia jest poprawny, ale kompilator ma podstawy ostrzegać i stąd pytanie jak sobie z tym poradzić.

 
var
 Ini: TIniFile;
 Plik: string;
 i: Integer;
 StaryProfil: Boolean;
begin
 Plik := ExtractFilePath(Application.ExeName) + 'abc.ini';
 StaryProfil := FileExists(Plik);
 if StaryProfil then Ini := TIniFile.Create(Plik);

 //....
 for i := 0 to 100 do
   begin
    //...
    if StaryProfil {lub Assigned(Ini)} then Ini.WriteString(...);  // <--------- Ini nie została zainicjowana
    //...
   end;

 if StaryProfil then Ini.Free;
end;

Można jakoś to obejść, ale po co w pętli mam wywoływać 100x Ini := TIniFileCreate(Plik); ?
Przecież zmienna "StaryProfil" nie jest modyfikowana.

0

Może ini:=nil; dać na początku to się przestanie czepiać :P

0

bo kompilator to jest głupie bydle - nie ufa programiście, że nagle nie przyjdzie mu do głowy pomiędzy pierwszym a drugim ifem zmienić StaryProfil z False na True

1

Może tak

  if StaryProfil then
  begin
    Ini := TIniFile.Create(Plik);
    //....
    for i := 0 to 100 do
    begin
      //...
        Ini.WriteString(...);  // <--------- Ini nie została zainicjowana
      //...
     end;
     Ini.Free;
  end;
end;
0

Może ini:=nil; dać na początku to się przestanie czepiać :P

Zgadza się :)

if StaryProfil then Ini := TIniFile.Create(Plik)
else Ini := nil;
0

nie lepiej to zrobić normalnie tj. przykładowo w powyższym przypadku jeśli plik nie istnieje to wyjść z funkcji

1

Ale nie zawsze to jest wyjściem i dlatego ten wątek z pytaniem.

0

Jeżeli Ini będzie nil to da się na nim zrobić WriteString?

0

Ciesz się że w Delphi dostajesz tylko warning. Sprawdziłem przed chwilą, kompilator C# wali po prostu error w takiej sytuacji.

0

Ja normalnie zaczynam się Was bać... @Opi, dlaczego chcesz powtarzać w trzech miejscach warunek? Kompilator będzie krzyczał, bo według niego istnieje obawa, że jednak odwołasz się do obiektu, który nie jest zainicjowany; Jak widać warunków nie sprawdza, więc ostrzega;

var
  iniABC: TINIFile;
  sFileName: String;
  bOldProfile: Boolean;
  I: Integer;
begin
  sFileName := ExtractFilePath(Application.ExeName) + 'abc.ini';
  bOldProfile := FileExists(sFileName);

  if bOldProfile then
    begin
      iniABC := TINIFile.Create(sFileName);

      if Assigned(iniABC) then
        try
          for I := 0 to 99 do
            iniABC.WriteString('...', '...', '...');
        finally
          iniABC.Free();
        end;
    end;
end.

Dzięki takiej konstrukcji nie ma możliwości odwołać się do nieutworzonego w pamięci obiektu i stąd kompilator do nieczego się nie przyczepi;


Jeśli mimo wszystko chcesz użyć właśnie takiej kontrukcji - wykorzystaj:

{$WARNINGS OFF}

{ kod }

{$WARNINGS ON}

będziesz miał spokój z ostrzeżeniami kompilatora;

0
 

begin
 Plik := ExtractFilePath(Application.ExeName) + 'abc.ini';
 StaryProfil := true; //<--------- to powinno uspokoić kompilator przed sypaniem ostrzeżeń
 StaryProfil := FileExists(Plik);
(...)

Nie sprawdzałem w Delphi, ale takie mam podejrzenia :)

0

Nie rozwiąże, w tym momencie zrobiłeś tak, że wartość przypisana do StaryProfil nigdy nie zostanie użyta.

0

problem jest nie ze zmienną StaryProfil tylko z Ini.

0

A po jakiego diabła używasz zmiennej Stary Profil?
Przy Funkcji Create, jeżeli plik INI istnieje, to zostanie otwarty do edycji, zaś gdy go brak zostanie utworzony nowy !!!

 
var
 Ini: TIniFile;
 i: Integer;
begin
 Ini := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'abc.ini'); {jak plik istnieje zostanie otwarty do edycji, gdy go brak zostanie utworzony nowy !!! }

try
 //....
 for i := 0 to 100 do
   begin
    //...
    Ini.WriteString(...);  // tu sobie wpisuje...
    //...
   end;

  finally
 Ini.Free;
 end;
end;

Regards.

0

W tym przypadku plik zawsze zostaje utworzony, czyli powstanie pusty.
Zauważ, że jeśli plik powstanie, zapis do pliku będzie wykonany. A warunkiem jest zapis tylko wtedy, jeśli już istnieje.

0

wy dalej to męczycie?
już mówiłem - w podanym przypadku rozwiązaniem jest wyjście z funkcji
jeśli to nie jest rozwiązaniem to podaj cały kod bo wywróżyć ciężko

w ogóle ciekawi mnie jak nazwałeś tę funkcję
RóbCośAJakIstniejePlikToPrzyOkazjiWezDoNiegoCosZapisuj?

0

Ale nie mogę wyjść z tej procedury, gdyż musi się ona wykonać do końca. Tak samo pisałem, że nie może być warunku przed pętlą, gdyż jest to na równi z tym co w pętli (chodzi o sprawdzanie warunku if StaryProfil then).

Druga sprawa, w pętli wykonywane są inne kroki, a zapisywanie do Ini jest jednym z tych kroków. Dlatego przykład:

  if StaryProfil then
    begin
      iniABC := TINIFile.Create(sFileName);
 
      if Assigned(iniABC) then
        try
          for I := 0 to 99 do
            iniABC.WriteString('...', '...', '...');
        finally
          iniABC.Free();
        end;
    end;

nie pasuje, gdyż w pętli muszą być wykonane rzeczy niezależne od zmiennej StaryProfil.

Jednak zgodnie z powyższymi radami, zastosowałem ten sposób, pozbywając się zmiennej "StaryProfil", a odwołując się jedynie wtedy, jeśli Ini faktycznie jest utworzona.

var
 Ini: TIniFile;
 Plik: string;
 i: Integer;
begin
 Plik := ExtractFilePath(Application.ExeName) + 'abc.ini';
 if FileExists(Plik) then Ini := TIniFile.Create(Plik)
 else Ini := nil;

 for i := 0 to 10 do
   begin
    //...
    if Assigned(Ini) then Ini.WriteString('a','b','c');
    //...
   end;

 if Assigned(Ini) then Ini.Free;
end;

Jednak bardzo ważne jest tutaj zastosowanie właśnie Ini := nil. Bez tego AV pewny, gdyż warunek Assigned(Ini) jest spełniony.

0
Furious Programming napisał(a)

Jeśli chodzi o nil'owanie to tak, nie ma żadnych problemów; Trochę to dziwne, bo czasem gdy używa się obiektów w dalszych częściach procedury/funkcji to czasem (nie umiem dokładniej określić w jakich przypadkach) też kompilator każe obiekt/zmienną zainicjować; Nie rozumiem zbytnio tego; Często zmiennej używam dopiero po instrukcji warunkowej "if .. then" lub "case .. of" i wtedy kompilator woła, że zmienna niezainicjowana pomimo tego, że najpierw wpisuję do niej potrzebne informacje, a dopiero później wywołuję jakąś funkcje/procedure wykorzystującą tą zmienną

Zmienna powinna być zainicjowana poza blokiem if then. Jeśli próbujesz do niej przypisać wartość po raz pierwszy w blokach if/case to dostaniesz ostrzeżenie wtedy, gdy poza tymi blokami odwołujesz się do tej wartości.

Poniżej dostaniesz ostrzeżenie, bo przypisałeś wartość do i w bloku if then.

var
 i, j: Byte;
 x: Boolean;
begin
 x := True;
 if x then
   begin
    i := 2;
    Showmessage(IntToStr(i));
   end;

 j := i;
 ShowMessage(IntToStr(j));
end;

Ale w tym przypadku, już wszystko jest w porządku:

var
 i: Byte;
 x: Boolean;
begin
 x := True;
 if x then
   begin
    i := 2;
    Showmessage(IntToStr(i));
   end;
end;

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