TStringList i List index out of bounds DELPHI

0

Witam wszystkich

Tworzę sobie program.
Mam pewien problem w procedurze:

 if Form6.RadioButton2.Checked then
        Form3.ProgressBar2.StepIt
        else
        Form3.ProgressBar1.StepIt;
        Randomize;
        repeat
        i:=Random(LiczbaLini2);                   // losowanie pytania, przypisanie go do zmiennej slash
        slash:=Lista2.Strings[i];
        until slash='///';
        slash:=Lista2.Strings[i+1];
        Form3.Pytanie.Caption:=slash;

I tutaj wywala mi błąd o treści że List index out of bounds( 'jakas wartosc').
Mam druga procedure praktycznie identyczną:

 
if Form6.RadioButton2.Checked then
        Form3.ProgressBar2.StepIt
        else
        Form3.ProgressBar1.StepIt;
        Randomize;
        repeat
        i:=Random(LiczbaLini1)+1;                   // losowanie pytania, przypisanie go do zmiennej slash
        slash:=Lista1.Strings[i];
        until slash='///';
        slash:=Lista1.Strings[i+1];
        Form3.Pytanie.Caption:=slash;

I w tym przypadku nie mam żadnych błędów.
Co jest nie tak w tej pierwszej procedurze. Błąd występuje tu:

 w:=res[1];
    gwarancja;
    if w<=4 then
    losujpytanie1;
    if w>4 then
    losujpytanie2; 

W przypadku losujpytanie1 wszystko jest super, a gdy dochodzi do losujpytanie2 to wyskakuje w/w błąd.

0

I tutaj wywala mi błąd o treści że List index out of bounds( 'jakas wartosc').

Masz racje, przecież nieważne jest JAKI błąd ci wyskakuje, liczy się to że WYSKAKUJE i zachowasz się jak enduser i oddasz swój program do serwisu.

Błąd występuje tu:

A mi się wydaje że wystąpił wyżej?

Naucz się opisywać problemy i zapytaj jeszcze raz. Pamiętaj że my nie wiemy tego co ty.

0

Wyrażenie i:=Random(LiczbaLini2) daje liczbę z przedziału 0..LiczbaLini2-1

W wyrażeniu slash:=Lista1.Strings[i] i musi być w zakresie 0 do Lista1.Count-1

Randomize należy wywołać tylko raz w OnCreate formy.

0

Ok, więc treść błędu:

Project Milionerzy.exe raised exception class EStringListError with message 'List index out of bounds(248)'. Process stopped. Use step or Run to contiune.

Błąd jest w procedurze którą napisałem jako pierwszą, a pojawia się gdy program dochodzi do momentu wywołania procedury 'losujpytanie2' i też nie za każdym razem tylko w losowo wybranych momentach.

0
pelsta napisał(a):

Wyrażenie i:=Random(LiczbaLini2) daje liczbę z przedziału 0..LiczbaLini2-1

W wyrażeniu slash:=Lista1.Strings[i] i musi być w zakresie 0 do Lista1.Count-1

Randomize należy wywołać tylko raz w OnCreate formy.

Okej, wprowadzę poprawki i zobaczymy.

0

Więc Randomize wywołałem tylko raz, i:=Random(LiczbaLini2) poprawione.
Tylko teraz mi wytłumacz jak możesz jeszcze tą ostatnią podpowiedź. Wydaję mi się że i jest z przedziału LiczbaLini1 w tym co napisałem.
Jak na razie błąd nie wyskoczył. Ale tak jak napisałem nie zawsze się pojawia. Będe testował.

0
Maxeppc napisał(a):

Więc Randomize wywołałem tylko raz, i:=Random(LiczbaLini2) poprawione.
Tylko teraz mi wytłumacz jak możesz jeszcze tą ostatnią podpowiedź. Wydaję mi się że i jest z przedziału LiczbaLini1 w tym co napisałem.
Jak na razie błąd nie wyskoczył. Ale tak jak napisałem nie zawsze się pojawia. Będe testował.

Niestety błąd znowu wystąpił.

0
Maxeppc napisał(a):
        repeat
        i:=Random(LiczbaLini2);                   // losowanie pytania, przypisanie go do zmiennej slash
        slash:=Lista2.Strings[i];
        until slash='///';
        slash:=Lista2.Strings[i+1];

I tutaj wywala mi błąd o treści że List index out of bounds( 'jakas wartosc').

Co to jest LiczbaLini2?
Załóżmy że jest to liczba elementów w Lista2.
Załóżmy, że LiczbaLini2=10 i wylosowało się i:=Random(LiczbaLini2)=9 i nastąpiło wyjście z pętli repeat.
Co się stanie przy próbie wykonania slash:=Lista2.Strings[i+1]?

0

Wtedy do slasha przypisuje to co jest pod 11 polem w Lista2.
Jest też że powtarza randoma dopóki nie znajdzie '///'.

0

Nie.
Wtedy wykonałaby się instrukcja slash:=Lista2.Strings[10] i program zakończyłby się błędem o którym pisałeś.

0

Aha, no tylko że w liście po ostatniej linijce która zawiera '///' jest jeszcze 5 linijek.
Czyli losować liczbe z przedziału (LiczbaLini2-6)??

0

Upewnij się co dokładnie jest w tej liście.
Ustaw Breakpointa w miejscu gdzie można spodziewać się błędu (typuję linię z slash:=Lista2.Strings[i+1]) i sprawdzaj zmienne.

0

Tylko jeszcze jedno pytanko, dlaczego identyczna procedura działa. Zmienione są tylko LiczbaLini i Lista. Obie listy zawierają to samo..

0

Błąd masz przede wszystkim w stylu programowania, a z tego wynikają błędy w samym kodzie, tutaj:

        repeat
        i:=Random(LiczbaLini1)+1;                   // losowanie pytania, przypisanie go do zmiennej slash
        slash:=Lista1.Strings[i];
        until slash='///';
        slash:=Lista1.Strings[i+1];
  1. Zmienna "LiczbaLini1" ma błędną nazwę z 3 powodów:
  • nie jest to liczba linii (bo gdyby była to ostatnia linijka MUSI się wywalić)
  • masz literówkę "Lini" zamiast "Linii"
  • stosujesz jakąś "1" w nazwie tylko po to żeby była unikalna - za to powinno być linijką po łapach
  1. Nazwę "i" stosuje się tylko w iteracjach (gdy bierzesz kolejne elementy struktury).
    Gdy bierzesz wybrany element stosuj nazwę "pos", "idx", "index", "indeks".

  2. Przed pętlą policz (i pokaż jak to robisz) zakres na którym chcesz pracować, np:

    MaxNrLinii = Lista1.Count - 2;

    if MaxNrLinii >= 0 then
    begin
      repeat
          idx := Random(MaxNrLinii+1);  // losowanie pytania, przypisanie go do zmiennej slash
          slash := Lista1.Strings[idx];
      until slash='///';
    
      wynik := Lista1.Strings[idx+1]; // to juz nie slash tylko wynik
    end
    else
    begin
       wynik := '';
    end;

Ważne żeby zmienna MaxNrLinii miała jakiś sens - tutaj jest to ostatni możliwy nr linii.

0
vpiotr napisał(a):

Gdy bierzesz wybrany element stosuj nazwę "pos", "idx", "index", "indeks".

Raczej nie należy stosować nazwy Pos (teoretyczne Index też nie), gdyż ta pierwsza to nazwa funkcji z modułu System, który domyślnie jest zawsze w projekcie.

0
Opi napisał(a):
vpiotr napisał(a):

Gdy bierzesz wybrany element stosuj nazwę "pos", "idx", "index", "indeks".

Raczej nie należy stosować nazwy Pos (teoretyczne Index też nie), gdyż ta pierwsza to nazwa funkcji z modułu System, który domyślnie jest zawsze w projekcie.

Tak, w przypadku Delphi / Pascal-a masz rację. Aktualnie programuję w kilku językach równolegle (najmniej chyba w Pascalu), dlatego o tym zapomniałem.

Przy okazji znalazłem standard który niby opisuje to co uznawał Borland, ale ten standard mógłby być o wiele dłuższy (kiedyś podobny napisałem na potrzeby pracodawcy - na podstawie VCL - standard nazewnictwa jest na pewno dłuższy):

http://edn.embarcadero.com/article/10280#3.5

0
vpiotr napisał(a):

Błąd masz przede wszystkim w stylu programowania, a z tego wynikają błędy w samym kodzie, tutaj:

        repeat
        i:=Random(LiczbaLini1)+1;                   // losowanie pytania, przypisanie go do zmiennej slash
        slash:=Lista1.Strings[i];
        until slash='///';
        slash:=Lista1.Strings[i+1];
  1. Zmienna "LiczbaLini1" ma błędną nazwę z 3 powodów:
  • nie jest to liczba linii (bo gdyby była to ostatnia linijka MUSI się wywalić)
  • masz literówkę "Lini" zamiast "Linii"
  • stosujesz jakąś "1" w nazwie tylko po to żeby była unikalna - za to powinno być linijką po łapach
  1. Nazwę "i" stosuje się tylko w iteracjach (gdy bierzesz kolejne elementy struktury).
    Gdy bierzesz wybrany element stosuj nazwę "pos", "idx", "index", "indeks".

  2. Przed pętlą policz (i pokaż jak to robisz) zakres na którym chcesz pracować, np:

    MaxNrLinii = Lista1.Count - 2;

    if MaxNrLinii >= 0 then
    begin
      repeat
          idx := Random(MaxNrLinii+1);  // losowanie pytania, przypisanie go do zmiennej slash
          slash := Lista1.Strings[idx];
      until slash='///';
    
      wynik := Lista1.Strings[idx+1]; // to juz nie slash tylko wynik
    end
    else
    begin
       wynik := '';
    end;

Ważne żeby zmienna MaxNrLinii miała jakiś sens - tutaj jest to ostatni możliwy nr linii.

tylko ta procedura działa poprawnie. Nie działa ta druga, losujpytanie2. Na początku umieściłem kod do niej. Losujpytanie1 jeszcze mi sie nie wysypała ani razu. Ale popracuje nad nią jeśli jest zła.

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