2013-02-28 19 views
7

Wystąpił problem polegający na tym, że mój kod został odłączony przy próbie użycia funkcji size() na liście. Na polecenie stackoverflow :-) Skonstruowałem minimalny przypadek, w którym występuje błąd segfault (w wywołaniu inventory.size() poniżej). Jest:Konfiguracja zestawu w konstruktorze oznacza awarię później

#include <list> 

class Thing {}; 

class Player { 
private: 
    int xpCalcArray[99]; 
    std::list<Thing*> inventory; 

public: 
    Player(); 

    int addToInv(Thing& t); // return 1 on success, 0 on failure 
}; 

Player::Player() { 
    // set up XP calculation array 
    for (int i=1; i<100; i++) { 
    if (i<=10) { 
     xpCalcArray[i] = i*100; 
    } 
    if (i>10 && i<=50) { 
     xpCalcArray[i] = i*1000; 
    } 
    if (i>50 && i<=99) { 
     xpCalcArray[i] = i*5000; 
    } 
    } 
} 

int Player::addToInv(Thing& t) { 
    if (inventory.size() == 52) { 
    return 0; 
    } else { 
     inventory.push_back(&t); 
    } 
    return 1; 
} 

int main(int argc, char *argv[]) { 
    Thing t; 
    Player pc; 
    pc.addToInv(t); 
    return 1; 
} 

Zauważyłem, że kiedy usunąć utworzenie tablicy w cosntructor gracza, to działa dobrze, więc to wydaje się być problemem. Co ja robię źle?

+2

+1: TESTCASE! Doskonały! –

Odpowiedz

2

Użytkownik uzyskuje dostęp poza granicami macierzy. Takie postępowanie powoduje niezdefiniowane zachowanie, więc nie ma żadnego logicznego wytłumaczenia dla wszystkiego, co nastąpi później. Rozmiar twojej tablicy to 99, a więc ostatni indeks to 98. Twoja pętla for idzie jednak do 99.

Albo Nakręć rozmiar tablicy 100:

int xpCalcArray[100]; 

stonie stan for do i < 99.

4

Masz dostęp do swojej macierzy poza granicami, co skutkuje niezdefiniowanym zachowaniem . Poprawny zakres indeksu dla tej tablicy

int xpCalcArray[99]; 

wynosi od 0 do 98. uzyskiwania dostępu indeks 99 tutaj:

if (i>50 && i<=99) { 
    xpCalcArray[i] = i*5000; 
} 

Twój zewnętrzna pętla powinna być

for (int i=0; i<99; i++) { ... } 

Uwaga zacznę od 0 , chociaż jest to założenie, że faktycznie chcesz uzyskać dostęp do pierwszego elementu.

Wtedy twój ostateczny warunek może być uproszczone do

if (i>50) { 
    xpCalcArray[i] = i*5000; 
} 

Jeśli zamierza wykorzystać rozmiar 100 tablicę, to trzeba

int xpCalcArray[100]; 

następnie pętlę między int i=0; i<100;.

+2

Oczywiście można by użyć * stałej stałej * zamiast kodowania twardego 50, 98, 99 i 100 wszędzie ... –

+0

Dziękuję wszystkim. Doh. – KHekkus

2

Nadpisujesz tablicę 99 int s, próbując zmodyfikować 100-ty element → (zamiast 1. → 99-ty).

W twoim przypadku, to zdarza się, aby zastąpić część pamięci w obrębie std::list<Thing*> (który istnieje w pamięci bezpośrednio po tablicy — nie zawsze, ale widocznie dla ciebie dzisiaj), a więc, gdy spróbujesz użyć listy, wszystkie piekło rozpada się, gdy dane jego wewnętrznego członka nie są już takie, jak sądzili.

1

Ty xpCalcArray jest zdefiniowany od 0 do 98 (ma 99 elementów dużych).

Twoja pętla przechodzi od 0 do 99, biorąc 100 kroków.

Ostatni cykl pętli, zapisuje xpCalcArray w lokalizacji 99, która nie istnieje. To (pośrednio) powoduje twoją awarię segmentacji, jak pokazuje the answer of Lightness Races in Orbit.

więc zwiększyć rozmiar xpCalcArray przez 1:

int xpCalcArray[100]; 
+0

Powoduje ono, że _pośrednio_ powoduje błąd segmentacji. Jedyną bezpośrednią konsekwencją jest tutaj wywołanie UB. –

+0

Tak, masz rację, twoje dodatkowe wyjaśnienie przyczyny jest doskonałe! – Veger

+0

Bez znajomości logiki kodu, zwiększenie rozmiaru tablicy niekoniecznie jest właściwym rozwiązaniem. Może tak być, ale nie możemy być pewni. – juanchopanza

Powiązane problemy