• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dlaczego program crashuje?

Object Storage Arubacloud
0 głosów
282 wizyt
pytanie zadane 2 marca 2018 w C i C++ przez Kuba321 Użytkownik (730 p.)

Dzień dobry,

Jakiś czas temu napisałem pewien kod (kod na ideone), nie jest on dokończony, ale nie potrafię zrozumieć, dlaczego dla przykładowych danych crashuje w linijce, w której odwołuję się do dynamicznej dwuwymiarowej tablicy, niezależnie, do którego pola bym się odwołał, czy to do 0,0; czy też do innego konkretnego. Program kompiluje się, ale crashuje po wpisaniu przykładowych danych.

Kod:

#include <iostream>
#include <queue>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(0);
    int il,kolumny,wiersze,xbohatera,ybohatera,aktx,akty,popx,popy;
    cin>>il;
    for(int i = 0; i < il; i++)
    {
        cin>>wiersze>>kolumny;
        char **tab;
        tab = new char*[wiersze];
        int **odl;
        odl = new int*[wiersze];
        for(int j = 0; j < wiersze; j++)
        {
            tab[j]=new char[kolumny];
            odl[j]=new int[kolumny];
            for(int k = 0; k < kolumny; k++)
            {
                cin>>tab[j][k];
                if(tab[j][k]=='@')
                {
                    xbohatera=k;
                    ybohatera=j;
                }
                odl[j][k]=-1;
            }
        }
        cout<<tab[0][0];
        //tu nalezy przygotowac i rozpoczac przeszukiwanie
        queue <int> wspx;
        queue <int> wspy;
        wspx.push(xbohatera);
        wspy.push(ybohatera);
        popx=xbohatera;
        popy=ybohatera;
        odl[ybohatera][xbohatera]=0;
        cout<<odl[ybohatera][xbohatera];
        while(wspx.empty()!=true)
        {
            cout<<'x';
            aktx=wspx.front();
            wspx.pop();
            akty=wspy.front();
            wspy.pop();
            //oznaczenie sasiadujacych kropek i plusow odlegloscia i dodanie ich wspolrzednych do kolejki
            if(aktx-1>-1)
            {
                if(tab[akty][aktx-1]=='.'||tab[akty][aktx-1]=='+') //odwiedzic tylko, jezeli odwiedzenie mozliwe
                {
                    if(odl[akty][aktx-1]==-1) //odwiedzic tylko, jezeli nieodwiedzone
                    {
                        odl[akty][aktx-1]=odl[popy][popx]+1;
                        wspx.push(aktx-1);
                        wspy.push(akty);
                        if(tab[akty][aktx-1]=='>') //jezeli koniec
                        {
                            cout<<odl[popy][popx]+1<<endl;
                            break;
                        }
                    }
                }
            }
            if(aktx+1<wiersze)
            {
                if(tab[akty][aktx+1]=='.'||tab[akty][aktx+1]=='+') //odwiedzic tylko, jezeli odwiedzenie mozliwe
                {
                    if(odl[akty][aktx+1]==-1) //odwiedzic tylko, jezeli nieodwiedzone
                    {
                        odl[akty][aktx+1]=odl[popy][popx]+1;
                        wspx.push(aktx+1);
                        wspy.push(akty);
                        if(tab[akty][aktx+1]=='>') //jezeli koniec
                        {
                            cout<<odl[popy][popx]+1<<endl;
                            break;
                        }
                    }
                }
            }
            if(akty-1>-1)
            {
                if(tab[akty-1][aktx]=='.'||tab[akty-1][aktx]=='+') //odwiedzic tylko, jezeli odwiedzenie mozliwe
                {
                    if(odl[akty-1][aktx]==-1) //odwiedzic tylko, jezeli nieodwiedzone
                    {
                        odl[akty-1][aktx]=odl[popy][popx]+1;
                        wspx.push(aktx);
                        wspy.push(akty-1);
                        if(tab[akty-1][aktx]=='>') //jezeli koniec
                        {
                            cout<<odl[popy][popx]+1<<endl;
                            break;
                        }
                    }
                }
            }
            if(akty+1<kolumny)
            {
                if(tab[akty+1][aktx]=='.'||tab[akty+1][aktx]=='+') //odwiedzic tylko, jezeli odwiedzenie mozliwe
                {
                    if(odl[akty+1][aktx]==-1) //odwiedzic tylko, jezeli nieodwiedzone
                    {
                        odl[akty+1][aktx]=odl[popy][popx]+1;
                        wspx.push(aktx);
                        wspy.push(akty+1);
                        if(tab[akty+1][aktx]=='>') //jezeli koniec
                        {
                            cout<<odl[popy][popx]+1<<endl;
                            break;
                        }
                    }
                }
            }
            popx=aktx;
            popy=akty;
            if(wspx.empty()==true)
            {
                cout<<"NIE"<<endl;
                break;
            }
        } //nawias petli while

        for(int j = 0; j < wiersze; j++)
        {
            delete [] tab[j];
            delete [] odl[j];
        }
        delete [] tab;
        delete [] odl;

    }
    return 0;
}

Przykładowe dane:

1
4 8
....#...
.##.#.#.
.##.#.#.
.@#...#>

Pozdrawiam

komentarz 2 marca 2018 przez marcin99b Szeryf (82,180 p.)
zapoznaj sie z debuggerem - możesz prześledzić co przechowuje określona zmienna, w określonej chwili
komentarz 2 marca 2018 przez Kuba321 Użytkownik (730 p.)
Nie mam zbyt dużego doświadczenia w debuggerach, ale próbowałem i nic nie znalazłem. Mogę jeszcze napisać, że jeżeli skopiuję jeden fragment z deklaracją tablic i będę próbował się odwołać do dowolnych pól, będzie działać. Bawiłem się nim też w ten sposób, że dopisywałem cout<<'x'<<endl; i sprawdzałem, czy wypisało x, a jeżeli nie, to uznałem, że w danej linijce coś jest nie tak.
komentarz 2 marca 2018 przez marcin99b Szeryf (82,180 p.)
hm
a jaką wiadomość błędu dostajesz?
nie pisze w c++, ale powinieneś mieć try{}catch(){}

sprawdź w tym miejscu, gdzie wywala błąd
w sumie powinno być napisane w np IDE albo w chwili wywalenia programu

1 odpowiedź

0 głosów
odpowiedź 3 marca 2018 przez Piotr Batko Stary wyjadacz (13,190 p.)
wybrane 3 marca 2018 przez Kuba321
 
Najlepsza

Uruchomiłem Twój kod przy pomocy debuggera. Wkleiłem dane wejściowe jakie tu podałeś. Program się wysypał. W tym momencie debugger wypisał: Program received signal SIGSEGV, Segmentation fault. Oznacza to, że program próbował się dostać do pamięci, której nie zaalokował. Błąd wystąpił w linii 104, a więc tu:

if(tab[akty+1][aktx]=='.'||tab[akty+1][aktx]=='+')

Debugger ponadto pokazywał obecnie przechowywane w zmiennych wartości.

Zmienna akty jest równa 3 i w tym momencie program wykonuje instrukcję tab[akty+1][aktx] czyli tab[4][aktx]. Ta tablica nie ma w sobie wiersza o indeksie 4; możesz korzystać jedynie z wierszy o indeksach 0, 1, 2, 3.

komentarz 3 marca 2018 przez Kuba321 Użytkownik (730 p.)
Dzięki za odpowiedz, debugger pokazywał mi to samo, ale najważniejszej rzeczy nie rozumiem. Dlaczego program nie wykonuje instrukcji w linijkach 59 i 63, które celowo tam umieściłem, żeby się dowiedzieć, gdzie jest blad. Przecież zgodnie z moja logika, ze program to lista poleceń, mój program powinien najpierw wypisać wartość tablicy odl do której się odwołuje i znak x, a dopiero potem się zcrashowac napotykając felernego if’a.
komentarz 3 marca 2018 przez Piotr Batko Stary wyjadacz (13,190 p.)

Linia 59 to wspy.push(akty), a 63 to break. Czy na pewno miałeś na myśli te linie?

Myślę, że Twój obecny problem polega na niewiedzy o buforowaniu cout-a. Wykonanie instrukcji cout << 'x' nie spowoduje jeszcze wypisania iksa na ekran. Ten tekst trafia do bufora w pamięci ram i zostanie wypisany później, gdy zajdzie taka potrzeba. Na przykład wtedy, gdy napiszesz cin >> var - wtedy zostaną wyświetlone znaki z bufora - albo gdy napiszesz cout << endl lub cout << flush. Z tego co na szybko sprawdziłem na StackOverflow wynika, że opróżnianie bufora (tzn. pojawianie się znaczków na ekranie) jest zależne od implementacji, czyli na różnych kompilatorach, możesz dostać różne wyniki.

Spróbuj zmusić swój program do wypisania tego iksa w tym momencie gdy piszesz cout instrukcją cout << 'x' << flush i daj znać, czy teraz wszystko działa zgodnie z oczekiwaniami :)

komentarz 3 marca 2018 przez Kuba321 Użytkownik (730 p.)
Przepraszam, mój błąd z tą linią (pisałem to ze starego smartphone ze starą przeglądarką). Chodziło o linijki 42 i 45. Jeśli chodzi o flush, wszystko działa zgodnie z oczekiwaniami. Gdzie mogę dowiedzieć się więcej o działaniu bufora i kompilatorów? Bo zauważam, że np moje gcc jakby samo optymalizuje kod, w sensie kiedyś bawiłem się w mierzenie czasu dodając zbędne instrukcje, które jakby nie wykonywały się. Jeśli chodzi o prawdziwy problem u mnie, to nie był nim crash, bo jego szybko da się naprawić, ale dlaczego przed crashem nie pojawia się x. Podejrzewałem gcc, że znowu coś "sknocił" ;)
komentarz 3 marca 2018 przez mokrowski Mędrzec (155,460 p.)

Ostatnią rzeczą którą powinieneś brać pod uwagę jest to że "gcc ma błąd", "gcc coś sknocił". Owszem, jest jakiś procent prawdopodobieństwa że tak może być. Jest on jednak bardzo mały i gratulował bym wręcz Ci że taki błąd znalazłeś :-)

Często wystarcza dodanie do kompilacji standardowych przełączników ostrzeżeń. Same komunikaty naprowadzają na potencjalne błędy. Na zachętę wynik z clang++ do własnego prześledzenia:

crashed.cpp:15:25: warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion]
        tab = new char*[wiersze];
              ~~~       ^~~~~~~
crashed.cpp:17:24: warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion]
        odl = new int*[wiersze];
              ~~~      ^~~~~~~
crashed.cpp:20:29: warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion]
            tab[j]=new char[kolumny];
                   ~~~      ^~~~~~~
crashed.cpp:21:28: warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion]
            odl[j]=new int[kolumny];
                   ~~~     ^~~~~~~
crashed.cpp:39:14: warning: variable 'xbohatera' may be uninitialized when used here [-Wconditional-uninitialized]
        popx=xbohatera;
             ^~~~~~~~~
crashed.cpp:9:37: note: initialize the variable 'xbohatera' to silence this warning
    int il,kolumny,wiersze,xbohatera,ybohatera,aktx,akty,popx,popy;
                                    ^
                                     = 0
crashed.cpp:40:14: warning: variable 'ybohatera' may be uninitialized when used here [-Wconditional-uninitialized]
        popy=ybohatera;
             ^~~~~~~~~
crashed.cpp:9:47: note: initialize the variable 'ybohatera' to silence this warning
    int il,kolumny,wiersze,xbohatera,ybohatera,aktx,akty,popx,popy;
                                              ^
                                               = 0

 

komentarz 3 marca 2018 przez Kuba321 Użytkownik (730 p.)
Piszac, ze gcc coś knoci, chodzi mi o to, ze np. automatyczna optymalizacja czy inne moduły, na których się nie znam, czasami sprawiają, ze program działa nieco inaczej, niż zamierzałem, np jakby pomija niektóre instrukcje

Podobne pytania

0 głosów
1 odpowiedź 283 wizyt
pytanie zadane 4 lipca 2017 w Systemy operacyjne, programy przez EdeX Mądrala (5,110 p.)
0 głosów
2 odpowiedzi 416 wizyt
pytanie zadane 21 listopada 2017 w C i C++ przez Sic Dyskutant (8,510 p.)
–3 głosów
3 odpowiedzi 476 wizyt
pytanie zadane 20 stycznia 2016 w C i C++ przez AdiM Nowicjusz (210 p.)

92,579 zapytań

141,429 odpowiedzi

319,657 komentarzy

61,962 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...