Nowe posty

xx Dystrybucja pod HP Omen (6)
Wczoraj o 23:30:08
xx [Poradnik] Wyszukiwanie Sterowników (2)
Wczoraj o 21:08:23
lamp Problem z Linux Lite po instalacji (0)
Wczoraj o 19:50:30
xx Ile pingwinów? (1)
Wczoraj o 08:59:24
xx konfiguracja pale moon (0)
2024-03-24, 21:53:42
xx Plasma 6 w Neonie ssie trochę mniej ... (10)
2024-03-23, 02:38:11
xx problem z instalacja sterowników do karty sieciowej (3)
2024-03-18, 18:10:16
xx Plik abc.001 (1)
2024-03-17, 17:48:27
xx Zlecę dopracowanie programu w MatLab (0)
2024-03-13, 15:28:40
xx Linux Mint 21.3 XFCE brak dźwieku po paru minutach (karta muzyczna zintegrowana) (5)
2024-03-12, 23:07:01

Autor Wątek: Vector  (Przeczytany 4627 razy)

Edzio123

  • Gość
Vector
« dnia: 2014-02-03, 13:24:00 »
Wiatm wszystkich forumowiczów!
Robię sobie ćwiczenie z wektorem i "sypnęła" mi się pamięć.
Nie mogę wyczaić co jest źle w tym kodzie:

#include
#include
using namespace std;

class osoba {
    private:
        char* nazwisko;
        int len;
    public:
        osoba(const char* n = NULL);
        friend ostream &operator<<(ostream &s, const osoba &o);
        friend ostream &operator<<(ostream &s, const osoba *wsk);
};
//******************************************************************8
osoba::osoba(const char *n){
    len = strlen(n);
    nazwisko = new char[len+1];
    strcpy(nazwisko,n);
}
ostream &operator<<(ostream &s, const osoba &o){
    s << o.nazwisko;
    return s;
}

ostream &operator<<(ostream &s, const osoba *wsk){
    s << wsk->nazwisko;
    return s;
}

const int pojemnosc_wektora = 15;

class vector{
        osoba tab1[pojemnosc_wektora];
        int ile_obiektow;
    public:
        vector(): ile_obiektow(0) { }
        int wstaw(const osoba &nowy, int gdzie = -1);  
        void usun(int nr)
   osoba &co_na(int pozycja) {return tab1[pozycja];} //przemyslec  //nie musi byc const?

        friend ostream& operator<<(ostream & stru, vector &x);
    private:
        void rozsun(int pozycja);
        void zsun(int nr);
};

ostream &operator<<(ostream &stru, vector &spis){
    stru << "     ";
    for (int i = 0; i < spis.ile_obiektow; i++){
        stru << i << ") " << spis.tab1[i] << " ";
    }
    stru << endl;
    return stru;
}
/**********************************************************************************************/
void vector::rozsun(int pozycja){
    for (int i = ile_obiektow; i < pozycja; i--){
        tab1[i] = tab1[i-1];
    }
}

void vector::zsun(int nr){
    for (int i = nr; i < ile_obiektow; i++){
        tab1[i] = tab1[i+1];
    }
}

int vector::wstaw (const osoba &nowy, int gdzie){
    if(ile_obiektow == pojemnosc_wektora){
        cout << "Wektor zostal juz zapelniony\\n";
        return 0;
    }
 if (gdzie < 0 || gdzie > ile_obiektow){  
        gdzie = ile_obiektow;
    }

    rozsun(gdzie);
    tab1[gdzie] = nowy;
    ile_obiektow++;
    return 1;
}

void vector::usun(int nr){
    if(nr < ile_obiektow){  
        zsun(nr);
        ile_obiektow--;
    }
}

 int main() {
    osoba
        wloch("Vivalidi"),
        niemiec("Bethoveen"),
        austriak("Mozart"),
        polak("Chopin");

    cout << "Przedstawia sie wloch: " << wloch << endl;

    osoba *kapelmistrz = &austriak;
                                          cout << "Kapelmistrzem jest dzisiaj: " << *kapelmistrz << endl;

    cout << polak << endl;

    vector muzycy;
    cout << "sizeof(muzycy)= " << sizeof(muzycy) <
    muzycy.wstaw(niemiec);
}

chmooreck

  • Gość
Vector
« Odpowiedź #1 dnia: 2014-02-03, 15:59:35 »
Zapoznaj się z gdb

Edzio123

  • Gość
Vector
« Odpowiedź #2 dnia: 2014-02-03, 16:09:47 »
Taaaak, skorzystalem z gdb.
I otrzymalem coć takiego:
Przedstawia sie wloch: Vivalidi
Kapelmistrzem jest dzisiaj: Mozart
Chopin
Przedstawia sie wloch: Vivalidi
Kapelmistrzem jest dzisiaj: Mozart
Chopin

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2_bsf () at ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S:52
52 ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S: No such file or directory.
in ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2_bsf () at ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S:52
52 ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S: No such file or directory.
in ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S
Sadze, że cos nie rak jest z funckja strlen..., ale wiem co...

Offline vanhelzing

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 314
    • Zobacz profil
Vector
« Odpowiedź #3 dnia: 2014-02-03, 18:41:55 »
Na pierwszy rzut oka, to masz niepoprawne warunki dla fora ().

void vector::rozsun(int pozycja){
    for (int i = ile_obiektow; i < pozycja; i--){
        tab1[i] = tab1[i-1];
    }
}
"i" zawsze na początku będzie większe od pozycji.

void vector::zsun(int nr){
    for (int i = nr; i < ile_obiektow; i++){
        tab1[i] = tab1[i+1];
    }
}
a tutaj, ostatnie przypisanie to tab1[ile_obiektow-1] = tab1[ile_obiektow]. tab1[ile_obiektow] jest chyba poza zakresem tablicy.
Mi to wygląda na naruszenie pamięci, a w takich przypadkach wskazywane komunikaty błędów trzeba brać z pewną rezerwą.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 3049
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Vector
« Odpowiedź #4 dnia: 2014-02-03, 19:09:29 »
Dodatkowo:

1. Masz konstruktor osoba z domyślnym parametrem inicjalizowanym na NULL.
2. W konstruktorze robisz bez sprawdzenia strlen tego parametru - niewykonalne dla argumentu NULL.
3. Vektor ma w środku tablicę osób , według standardu inicjalizowanych defaultem, czyli u Ciebie NULLem i stąd od razu strzał w strlen w konstruktorze.

Wystarczy poprawić deklarację konstuktora tak:

...
public:
        osoba(const char* n = "");
        friend ostream &operator<<(ostream &s, const osoba &o);
...
Jestem zbyt sponiewierany, żeby wczytywać się w kod kolegi VanHelsinga, ale przyjrzyj się jego uwagom.
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Edzio123

  • Gość
Vector
« Odpowiedź #5 dnia: 2014-02-03, 22:38:54 »
Dzięki chłopaki. Teraz modyfikuje moj kod i korzystam z szablonów, by stworzyć wektor.
#include
#include
using namespace std;

class osoba {
    private:
        char* nazwisko;
        int len;
    public:
        osoba(const char* n = " ");
        friend ostream &operator<<(ostream &s, const osoba &o);
        friend ostream &operator<<(ostream &s, const osoba *wsk);
};
//******************************************************************8
osoba::osoba(const char *n){
    len = strlen(n);
    nazwisko = new char[len+1];
    strcpy(nazwisko,n);
}
ostream &operator<<(ostream &s, const osoba &o){
    s << o.nazwisko;
    return s;
}

ostream &operator<<(ostream &s, const osoba *wsk){
    s << wsk->nazwisko;
    return s;
}

const int pojemnosc_wektora = 15;

template
class vector{
        twoj_typ tab1[pojemnosc_wektora];
        int ile_obiektow;
    public:
        vector(): ile_obiektow(0) { } //dynamicznie!!!
        int wstaw(const twoj_typ &nowy, int gdzie = -1);  
 void usun(int nr);
        twoj_typ &co_na(int pozycja) {return tab1[pozycja];}

        friend ostream& operator<<(ostream & stru, vector &x);
    private:
        void rozsun(int pozycja);
        void zsun(int nr);
};

template
ostream &operator<<(ostream &stru, vector &spis){
    stru << "     ";
    for (int i = 0; i < spis.ile_obiektow; i++){
        stru << i << ") " << spis.tab1[i] << " ";
    }
    stru << endl;
    return stru;
}
/**********************************************************************************************/
template
void vector::rozsun(int pozycja){
    for (int i = ile_obiektow; i > pozycja; i--){
        tab1[i] = tab1[i-1];
    }
}

template
void vector::zsun(int nr){
    for (int i = nr; i < ile_obiektow; i++){
        tab1[i] = tab1[i+1];
    }
}

template
int vector::wstaw (const twoj_typ &nowy, int gdzie){
    if(ile_obiektow == pojemnosc_wektora){
        cout << "Wektor zostal juz zapelniony\\n";
                                                             return 0;
    }

    if (gdzie < 0 || gdzie > ile_obiektow){   //?????????????????????????????????????
        gdzie = ile_obiektow;
    }

    rozsun(gdzie);
    tab1[gdzie] = nowy;
    ile_obiektow++;
    return 1;
}

template
void vector::usun(int nr){
    if(nr < ile_obiektow){  
        zsun(nr);
        ile_obiektow--;
    }
}

 int main() {
    osoba
        wloch("Vivalidi"),
        niemiec("Bethoveen"),
        austriak("Mozart"),
        polak("Chopin");

    cout << "Przedstawia sie wloch: " << wloch << endl;

    osoba *kapelmistrz = &austriak;
    cout << "Kapelmistrzem jest dzisiaj: " << *kapelmistrz << endl;
 vector muzycy;
    cout << "sizeof(muzycy)= " << sizeof(muzycy) <
Niestey podczas kopilacji dostaje błąd:
vector.cpp:42:71: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, vector&)’ declares a non-template function [-Wnon-template-friend]
vector.cpp:42:71: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Wydaje mi się, że operator << jest dobrze stworzony, ale jak widac coś mi się źle wydaje.

Mam rowniez pytanie do funkcji:
 friend ostream& operator<<(ostream & stru, vector &x);
Dlaczego do drugiego argumentu nie możemy użyć const?

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 3049
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Vector
« Odpowiedź #6 dnia: 2014-02-04, 20:41:27 »
Tu jest grubiej.

Deklaracja friend formalnie zachowuje się, jakby znajdowała się poza deklaracją klasy - czyli jak deklaracja normalnej funkcji. Różnica w stosunku do "zwykłej funkcji" to dosktęp do składowych prywatnych  tyle. W związku z tym parametr szablonowy klasy nie działa jak myślisz. Aby było poprawnie, ten kawałek kodu musi wyglądać tak:
...
        twoj_typ &co_na(int pozycja) {return tab1[pozycja];}

        template
        friend ostream& operator<< (ostream & stru, vector &x);
    private:
...
Czyli "wizualnie" to szablon w szablonie ale składniowo szablon obok szablonu. Musisz też użyć twoj_typ2 zamiast twoj_typ, bo nie można przykrywać parametrów szablonowych.

OT. Generalnie "podmiot" w operator<< deklaruje się jako const, tak jak zrobiłeś to w przypadku klasy osoba.
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Edzio123

  • Gość
Vector
« Odpowiedź #7 dnia: 2014-02-06, 20:02:00 »
Wielkie dzięki za wskazanie błędu, nie wiedziałem, że to tak działa...
Jednakże jeszcze nie rozumiem dlaczego w operatorze << , który wskazałem nie używamy const, tak jak mowi nam reguła.

Jeszcze popracowałem nad kodem:
#include
#include
using namespace std;

class osoba {
    private:
        char* nazwisko;
        int len;
    public:
        osoba(const char* n = " ");
        ~osoba();
        friend ostream &operator<<(ostream &s, const osoba &o);
        friend ostream &operator<<(ostream &s, const osoba *wsk);
};
//******************************************************************8
osoba::osoba(const char *n){
    len = strlen(n);
    nazwisko = new char[len+1];
    strcpy(nazwisko,n);
}
osoba::~osoba(){
        delete [] nazwisko;
}
ostream &operator<<(ostream &s, const osoba &o){
    s << o.nazwisko;
    return s;
}

ostream &operator<<(ostream &s, const osoba *wsk){
    s << wsk->nazwisko;
    return s;
}

const int pojemnosc_wektora = 15;
const int pojemnosc_wektora = 15;

template
class vector{
        twoj_typ *tab1;
        int ile_obiektow;
    public:
        vector( int ile_obiektow = 0){
        tab1 = new twoj_typ[pojemnosc_wektora];
        }
        ~vector(){
        delete [] tab1;
        }
        int wstaw(const twoj_typ &nowy, int gdzie = -1);
 void usun(int nr);
        twoj_typ &co_na(int pozycja) {return tab1[pozycja];}

        template
        friend ostream& operator<<(ostream & stru, vector &x);
    private:
        void rozsun(int pozycja);
        void zsun(int nr);
};
template
ostream &operator<<(ostream &stru, vector &spis){
    stru << "     ";
    for (int i = 0; i < spis.ile_obiektow; i++){
        stru << i << ") " << spis.tab1[i] << " ";
    }
    stru << endl;
    return stru;
}
/**********************************************************************************************/
template
void vector::rozsun(int pozycja){
    for (int i = ile_obiektow; i > pozycja; i--){
        tab1[i] = tab1[i-1];
    }
}

template
void vector::zsun(int nr){
    for (int i = nr; i < ile_obiektow; i++){
        tab1[i] = tab1[i+1];
    }
}

template
int vector::wstaw (const twoj_typ &nowy, int gdzie){
    if(ile_obiektow == pojemnosc_wektora){
        cout << "Wektor zostal juz zapelniony\\n";
                                                             return 0;
    }

    if (gdzie < 0 || gdzie > ile_obiektow){   //?????????????????????????????????????
        gdzie = ile_obiektow;
    }
 rozsun(gdzie);
    tab1[gdzie] = nowy;
    ile_obiektow++;
    return 1;
}

template
void vector::usun(int nr){
    if(nr < ile_obiektow){
        zsun(nr);
        ile_obiektow--;
    }
}

 int main() {
    osoba
        wloch("Vivalidi"),
        niemiec("Bethoveen"),
        austriak("Mozart"),
        polak("Chopin");

    cout << "Przedstawia sie wloch: " << wloch << endl;

    osoba *kapelmistrz = &austriak;
    cout << "Kapelmistrzem jest dzisiaj: " << *kapelmistrz << endl;
 vector muzycy;
    cout << "sizeof(muzycy)= " << sizeof(muzycy) <}
Czy możecie mi wskazać co jeszcze w tym kontenerze można dopracować? Wszelkie wskazówki będą mile widziane. :)
Wiem, wiem, pierwszym krokiem powinno być rozdzielenie kodu na kilka plików ale to nie jest problem.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 3049
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Vector
« Odpowiedź #8 dnia: 2014-02-08, 15:37:48 »
1. W założeniu, w standardowych przypadkach zapisanie obiektu do strumienia nie zmienia zawartości tego obiektu (choć może być to nieprawdą - obiekt może np zliczać swoje zapisania).
2. Jeżeli parametr podmiotu w operator<< oznaczysz jako const& to zyskujesz dwie cechy:
 * Jak się kopsniesz w kodzie i przypadkiem spróbujesz zmodyfikować obiekt, to kompilator cię obfuka (can't modify const object).
 * Jak parametr jest const&, to kompilator ma dodatkowe możliwości optymalizacji kodu, aż do poziomu włączenia funkcji jako inline i pracy na oryginale (skoro go nie zmieniasz, to ryba czy to kopia czy oryginał).
3. Oczywiście parametr strumienia w operator<< nie może być const, bo modyfikujesz strumień zapisując do niego.

Co poprawić?
* Jak już wchodzimy głębiej, to zastąpić char* przez std::string. Co nas stawia od razu przed zagadnieniem std::vector...
* Jak mamy implementować staw i usuń, po bardziej zastanowić się nad listą niż tablicą. Tutaj pojawia się zagadnienie big-oh (czyli oceny O).
- Czy będziemy częściej żądać elementu z konkretnej pozycji tablicy - wtedy rzeczywiście, tablica wygrywa, dostęp jest O(1), w liście jest to O(n)
- Czy będziemy sekwencyjnie przeglądać całą tablicę. Wtedy oba są O(n).
- Czy częściej będziemy wstawiać i usuwać elementy ze środka mając pozycję elementu - wtedy oba są O(n), w liście znalezienie jest O(n), wstawienie/usunięcie O(1) a w tablicy znalezienie jest O(1) a wstawienie/usunięcie jest O(n).
- Czy częściej będziemy wstawiać i usuwać elementy przed/za znanym elementem - tu wygrywa lista O(1) przed tablicą O(n).
- Czy będziemy implementować kolejkę/stos o stałej pojemności (wtedy lepiej sprawdza się tablica) czy o zmiennej (wtedy lepiej sprawdza się lista). I tablica i lista dają O(1) w tym wypadku, więc to bardziej sprawa wyczucia.

Itede, itepe.
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy