Naruszenie ochrony pamięci.

0

Mam problem z uruchamianiem kodu na Ubuntu, wyrzuca błąd "Naruszenie ochrony pamięci (zrzut pamięci)". Program działa na Windowsie, ale zależy mi na tym żeby na Ubuntu też się uruchamiał.

#include <iostream>
#include <fstream>
using namespace std;

struct SObiektyw {
    string rodzaj;
    float przeslona;
    float ogniskowa;
};
struct SAparat {
    string nazwa;
    int ilosc;
    SObiektyw * obiektyw;
};

void wczytaj( SAparat & aparaty ) {
    ifstream plik;
    plik.open( "dane.txt" );
    plik >> aparaty.nazwa >> aparaty.ilosc;
    if( aparaty.ilosc > 0 ) {
        aparaty.obiektyw = new SObiektyw[ aparaty.ilosc ];
    }
   
    for( int i = 0; i < aparaty.ilosc; ++i ) {
        plik >> aparaty.obiektyw[ i ].rodzaj >> aparaty.obiektyw[ i ].przeslona >> aparaty.obiektyw[ i ].ogniskowa;
    }
}

void wypisz( SAparat & aparaty ) {
    ofstream plik2;
    plik2.open( "dane2.txt" );
   
    plik2 << aparaty.nazwa << aparaty.ilosc;
    for( int i = 0; i < aparaty.ilosc; ++i ) {
        plik2 << aparaty.obiektyw[ i ].rodzaj << aparaty.obiektyw[ i ].przeslona << aparaty.obiektyw[ i ].ogniskowa;
    }
}

int zlicz( SAparat & aparaty ) {
    int licznik = 0;
    for( int i = 0; i < aparaty.ilosc; ++i ) {
        if( aparaty.obiektyw[ i ].ogniskowa > 50 ) {
            licznik++;
        }
    }
    return licznik;
}

void usun( SAparat & aparaty ) {
    delete[ ] aparaty.obiektyw;
}

int main() {
   
    SAparat aparaty;
    wczytaj( aparaty );
    wypisz( aparaty );
    cout << zlicz( aparaty );
    usun( aparaty );
    return 0;
}
0

lokalnie odpal w debbuger. Powinien ci pokazać linię z seg faultem. Jeśli nie to idź korkowo.
Sugeruję też sprawdzać przed czytaniem z pliku czy on istnieje.

Ale pierwsze do przerobienia jak to c++.

    SObiektyw * obiektyw;

Zmień to na vector np. std::vector<SObiektyw> mObiektyw;

1

segfault powoduje wywołanie funkcji.

void usun( SAparat & aparaty ) {
    delete[ ] aparaty.obiektyw;
}

Jest to błędne podejście. Poczytaj o destruktorach.

0

Debugger wyrzuca takie coś:
struct SObiektyw{
Exception has occurred.
Segmentation fault

Na stronce https://www.onlinegdb.com kod działa i debuguje się bez błędów.
Zwalnianie pamięci chyba też działa, bo komenda valgrind --leak-check=full ./main zwraca "no leaks possible".

0

Pomijając uwagę wyżej, że to jest zły sposób programowania, robisz

    if( aparaty.ilosc > 0 ) {
        aparaty.obiektyw = new SObiektyw[ aparaty.ilosc ];
    }

a potem już bez względu na wartość aparaty.ilosc, robisz

delete[ ] aparaty.obiektyw;

podczas gdy można to tylko robić, jeśli to new faktycznie zostało wykonane.

0

Mam taką dobrą praktykę, że o strukturach C++ jak zawierają elementy z biblioteki standardowej, z drugiej strony jak zawierają bufory, wskaźniki itd myślę jako o klasach (tak mam, wiem że nie jest to konieczne) z jawnym konstruktorem (jawny destruktor też nie zaszkodzi)
Dla mnie w C++ struktura to "struktura C z typami prostymi"

Druga z klas, posiadająca wskaźnik i nie posiadająca konstruktora, to dla mnie POWAŻNY błąd C++, całkiem możliwe związany z wyjątkiem

class SObiektyw {
public:
    SObiektyw (string a, float b, float c); 
    string rodzaj;
    float przeslona;
    float ogniskowa;
};
class SAparat {
public:
    SAparat ( ...) 
   {
       obiektyw = NULL; // oczywiście vector jest lepszy
 ....
   }
   ~ SAparat ()
    {
         if(obiektyw  != null)    /// vector lepszy
            delete ... 
    } 
    string nazwa;
    int ilosc;
    SObiektyw * obiektyw;
};

W dalszej kolejności bym szedł jak najdalej od tablicy w stylu C, w tym również uczynił grzebanie w buforze niedostępne, tylko przez konstruktor / metody

0

Zbuduj to z -ggdb3 -fsanitize=address przekazanym do GCC, powinno pomóc zlokalizować błąd.

0

Ja bym radził zacząć od tego żeby sprawdzić czy dane się poprawnie wczytały:

void wczytaj( SAparat & aparaty ) {
    ifstream plik;
    plik.open( "dane.txt" );
    plik >> aparaty.nazwa >> aparaty.ilosc;
    if( aparaty.ilosc > 0 ) {
        aparaty.obiektyw = new SObiektyw[ aparaty.ilosc ];
    }

Inaczej aparaty.ilosc jest niezainicjalizowane.

A druga sprawa że ten if powinien mieć drugą gałąź jeżeli inne funkcje potem będą na tym operować - aka else { ... = new SObiektyw[0] } (a takie usuń operuje).

2

Zacząłbym od:

#include <iostream>
#include <fstream>
using namespace std;

/*
struct SObiektyw {
    string rodzaj;
    float przeslona;
    float ogniskowa;
};
struct SAparat {
    string nazwa;
    int ilosc;
    SObiektyw * obiektyw;
};

void wczytaj( SAparat & aparaty ) {
    ifstream plik;
    plik.open( "dane.txt" );
    plik >> aparaty.nazwa >> aparaty.ilosc;
    if( aparaty.ilosc > 0 ) {
        aparaty.obiektyw = new SObiektyw[ aparaty.ilosc ];
    }

    for( int i = 0; i < aparaty.ilosc; ++i ) {
        plik >> aparaty.obiektyw[ i ].rodzaj >> aparaty.obiektyw[ i ].przeslona >> aparaty.obiektyw[ i ].ogniskowa;
    }
}

void wypisz( SAparat & aparaty ) {
    ofstream plik2;
    plik2.open( "dane2.txt" );

    plik2 << aparaty.nazwa << aparaty.ilosc;
    for( int i = 0; i < aparaty.ilosc; ++i ) {
        plik2 << aparaty.obiektyw[ i ].rodzaj << aparaty.obiektyw[ i ].przeslona << aparaty.obiektyw[ i ].ogniskowa;
    }
}

int zlicz( SAparat & aparaty ) {
    int licznik = 0;
    for( int i = 0; i < aparaty.ilosc; ++i ) {
        if( aparaty.obiektyw[ i ].ogniskowa > 50 ) {
            licznik++;
        }
    }
    return licznik;
}

void usun( SAparat & aparaty ) {
    delete[ ] aparaty.obiektyw;
}
*/

int main() {
/*
    SAparat aparaty;
    wczytaj( aparaty );
    wypisz( aparaty );
    cout << zlicz( aparaty );
    usun( aparaty );*/
    return 0;
}

Kompilacja, uruchomenie.

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