Strona 1 z 1

[C++] jak zapisać dużą listę dynamiczną do pliku?

: 12 cze 2011, 16:28
autor: Enkidu
Cześć,

mam problem jak zapisać dużą listę dynamiczną do pliku, żeby łatwo było ją wczytać a potem posortować itp.

Struktura wygląda tak:

Kod: Zaznacz cały

struct ksiazka{
     short int cena;
     string tytul;
     string nazwisko;
     string imie;
     short int ilosc;
     ksiazka *nastepny;
}
Napisałem coś takiego, ale nie działa zbyt dobrze:

Kod: Zaznacz cały

void zapisz(ksiazka *adres){
     ifstream file("baza.txt");
     if(file.good()){
          while(adres!= 0){
                 file << adres->tytul << endl << adres->imie << endl << adres->nazwisko << endl << adres->cena << endl << adres->ilosc << endl;
                 adres = adres->nastepny;
           }
     }
     file.close();
}
Proszę o pomoc!

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 12 cze 2011, 17:40
autor: bigfun
A nie działa w sensie jakim? wywala błąd, czy nie robi tego co byś chciał? napisz coś więcej.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 12 cze 2011, 18:02
autor: Enkidu
Wyskakuj mi błąd:

Kod: Zaznacz cały

error: no match for 'operator<<' in 'file << adres->ksiazka::tytul'
Używam Code::Block.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 12 cze 2011, 18:58
autor: skoczo

Kod: Zaznacz cały

#include <iostream>
#include <fstream>

using namespace std;

struct ksiazka{
     short int cena;
     string tytul;
     string nazwisko;
     string imie;
     short int ilosc;
     ksiazka *nastepny;
};

void zapisz(ksiazka *adres){
     ofstream file("baza.txt");
     if(file.good()){
          while(adres!= 0){
                 file << adres->tytul << endl << adres->imie << endl << adres->nazwisko << endl << adres->cena << endl << adres->ilosc << endl;
                 adres = adres->nastepny;
           }
     }
     file.close();
}

int main()
{
	ksiazka k;
	k.cena = 100;
	k.tytul = "tytul";
	k.nazwisko = "nazwisko";
	k.imie = "imie";
	k.ilosc = 1;
	k.nastepny = NULL;
	
	zapisz( &k);
	
	return 0;
}

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 12 cze 2011, 21:35
autor: Enkidu
Działa :D dzięki wielkie!

Mam jeszcze kilka pytań. Napisałem analogiczną funkcję do wczytywania:

Kod: Zaznacz cały

void wczytaj(ksiazka *&adres){
    ifstream file("baza.txt");
    if(file.good()){
        while(adres != NULL){
            file >> adres->tytul >> adres->imie >> adres->nazwisko >> adres->cena >> adres->ilosc;
            adres = adres->nastepny;
        }
    }
    file.close();
ale inicjalizacja nie działa:

Kod: Zaznacz cały

wczytaj( *k);
ani tak:

Kod: Zaznacz cały

wczytaj( *&k);
ani bez wskaźnika. Gdzie popełniłem błąd.

I jeszcze pytanie - jeśli będę chciał zrobić później sortowanie po każdym z elementów struktury, to czy jest jakiś sposób, żeby zrobić to na stringach, czy lepiej wprowadzić tablice char o wielkości "z zapasem pamięci"?

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 13 cze 2011, 01:04
autor: karmelek
I jeszcze pytanie - jeśli będę chciał zrobić później sortowanie po każdym z elementów struktury, to czy jest jakiś sposób, żeby zrobić to na stringach, czy lepiej wprowadzić tablice char o wielkości "z zapasem pamięci"?
Mając do stringów zdefiniowany komparator nie wiem gdzie widzisz problem.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 13 cze 2011, 01:48
autor: bigfun
Enkidu pisze: Napisałem analogiczną funkcję do wczytywania:

Kod: Zaznacz cały

void wczytaj(ksiazka *adres){
    ifstream file("baza.txt");
    if(file.good()){
        while(adres != NULL){
            file >> adres->tytul >> adres->imie >> adres->nazwisko >> adres->cena >> adres->ilosc;
            adres = adres->nastepny;
        }
    }
    file.close();
ale inicjalizacja nie działa:

Kod: Zaznacz cały

wczytaj( *k);
ani tak:

Kod: Zaznacz cały

wczytaj( *&k);
ani bez wskaźnika. Gdzie popełniłem błąd.
Wystarczy jak przekażesz wskaznik, nie potrzebujesz przekazywać referencji do wskaźnika. Przekazywanie referencji powoduje, ze kiedy przechodzisz po liście zmieniając wartość wskaznika *adres, nadpisujesz wartość oryginalnie przekazanego wskaznika. A więc najlepiej:

Kod: Zaznacz cały

ksiazka *k = new ksiazka;
wczytaj(k);
W funkcji wczytującej musisz jednak alokować pamięć dla kolejnych elementów na liście (Bo rozumiem, że przy wczytywaniu nie wiesz, ile masz ksiazek). Warunek na koniec listy (adress != NULL) jest więc bez sensu.

Kod: Zaznacz cały

void wczytaj(ksiazka *&adres){
    ifstream file("baza.txt");
    if(file.good()){
        while(!file.eof()){
            file >> adres->tytul >> adres->imie >> adres->nazwisko >> adres->cena >> adres->ilosc;
            adres->nastepny = new ksiazka;
            adres = adres->nastepny;
        }
    }
    file.close();

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 13 cze 2011, 10:52
autor: ilu2112
Jeżeli chodzi o zapis do pliku tylko po to, żeby potem móc wczytać zapisaną strukturę to czemu nikt jeszcze nie wspomniał o plikach binarnych?

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 16 cze 2011, 00:15
autor: Enkidu
Łał, niewypowiedziane dzięki! :)

Mam jeszcze pytanie - czy w funkcjach drukuj i wczytaj powinno znajdować się na końcu zamknięcie pliku? A propos sortowania stringów to mimo gotowego komparatora nie wiem jak robić to sortowanie i wyszukiwanie wg alfabetu :/ Ani w skrypcie ani w podręczniku Praata do C++ tego nie znalazłem :/

I już ostatnia prośba, czy moglibyście zerknąć na moją funkcję drukuj i dodaj? Drukuj po wczytaniu ostatniej struktury próbuje dalej wczytywać i wywala błąd.

Kod: Zaznacz cały

void drukuj(ksiazka *adres){
    cout << "Zawartosc listy:" << endl;
    if(!adres) return;
    cout << "Tytul ksiazki: " << adres->tytul << endl << "Nazwisko: " << adres->nazwisko << endl << "Imie: "<< adres->imie << endl << "Cena: "<< adres->rok << endl;
    if(adres!=NULL){
       drukuj(adres->nastepny);
    }
};
a tu jest dodaj:

Kod: Zaznacz cały

void dodaj(ksiazka *adres){
    ksiazka *adres;
    glowa = NULL;
    
    cout << "Podaj tytul ksiazki: ";
    adres = new ksiazka();
    string word;
    cin >> word;
    adres->tytul = word;

    cout << "\nPodaj nazwisko: ";
    cin >> word;
    adres->nazwisko = word;

//itd.

    adres = adres->nastepny;
    }
};
Jeszcze raz proszę o pomoc!

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 16 cze 2011, 00:50
autor: karmelek
Mam jeszcze pytanie - czy w funkcjach drukuj i wczytaj powinno znajdować się na końcu zamknięcie pliku? A propos sortowania stringów to mimo gotowego komparatora nie wiem jak robić to sortowanie i wyszukiwanie wg alfabetu :/ Ani w skrypcie ani w podręczniku Praata do C++ tego nie znalazłem :/
Z czym masz problem? Bierzesz dowolny algorytm sortowania liczbowego jak quicksort, merge, albo głupi insertion i w miejscu porównania wykonujesz operacje komparatorem. Zapewne sprowadzi się to do jednego ifa i wsio...

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 16 cze 2011, 02:06
autor: luzakwielki
ilu2112 pisze:Jeżeli chodzi o zapis do pliku tylko po to, żeby potem móc wczytać zapisaną strukturę to czemu nikt jeszcze nie wspomniał o plikach binarnych?
Widocznie nikogo nie interesuje to czy się szybko wczyta (binarnie nagłówek w którym zapisane jest ile jest wpisów przeczytać i jeden memcopy i wszystko jest wczytane w pamięci, bez marnowania czasu na analize treści tekstu), ani to, że jeśli już się uparł na tekstowe to tak wczytywać jak teraz sobie może na zaliczeniu w szkole, ale nie w realnym świecie (wystarczy, że będzie miał tytuł ze spacją jak np. Pan Tadeusz, i tytuł książki będzie miał Pan, a Tadeusz, zostanie już wczytany do imienia (nazwisko będzie miało "imie", a prawdziwego nazwiska wcale nie odczyta) - ktoś tu zapomniał, że takie wczytywanie nie wczytuje całej linijki, a do pierwszego białego znaku w tekście).

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 16 cze 2011, 09:41
autor: ilu2112
luzakwielki pisze:
ilu2112 pisze:Jeżeli chodzi o zapis do pliku tylko po to, żeby potem móc wczytać zapisaną strukturę to czemu nikt jeszcze nie wspomniał o plikach binarnych?
Widocznie nikogo nie interesuje to czy się szybko wczyta (binarnie nagłówek w którym zapisane jest ile jest wpisów przeczytać i jeden memcopy i wszystko jest wczytane w pamięci, bez marnowania czasu na analize treści tekstu), ani to, że jeśli już się uparł na tekstowe to tak wczytywać jak teraz sobie może na zaliczeniu w szkole, ale nie w realnym świecie (wystarczy, że będzie miał tytuł ze spacją jak np. Pan Tadeusz, i tytuł książki będzie miał Pan, a Tadeusz, zostanie już wczytany do imienia (nazwisko będzie miało "imie", a prawdziwego nazwiska wcale nie odczyta) - ktoś tu zapomniał, że takie wczytywanie nie wczytuje całej linijki, a do pierwszego białego znaku w tekście).
Dokładnie o tym myślałem, gdy pisałem swoją wiadomość. Enkidu, jeżeli coś robisz nawet na zwykłe zaliczenie w szkole to zrób to dobrze. Być może w przyszłości to wykorzystasz, a na pewno nabyta wiedza Ci się przyda. Rzuć okiem na pliki binarne. Chwila (dosłownie!) lektury pozwoli Ci na szybkie wczytywanie i zapisywanie struktur do pliku. Do tego nie będziesz miał problemów z białymi znakami w nazwach, tytułach itd.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 16 cze 2011, 19:31
autor: Enkidu
Hm, nawet nie wiedziałem, że to nie wczyta dłuższego tytułu... :/ Zmieniam to na plik binarny, dzięki za radę!

Jeszcze tylko mam prośbę o przyjrzenie się tym funkcjom na górze oraz wyjaśnienie jak zaimplementować ten komparator!

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 19 cze 2011, 10:51
autor: fraktal
Jako że to mój pierwszy post, serdecznie witam.

Implementacja komparatora

Dojdziemy do tego metodą prób i błędów.
Piszemy programik:

Kod: Zaznacz cały

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s1, s2, s3, s4;
    s1 = "a";
    s2 = "A";
    s3 = "ab";
    s4 = "ba";
    cout << (s1 < s2) << endl;
    cout << (s2 < s1) << endl;
    cout << (s3 < s4) << endl;
}
Wynikiem jest:

Kod: Zaznacz cały

0
1
1
Dochodzimy do następujących wniosków:
  • Litery większe są mniejsze niż małe (czyli trochę inaczej niż by wskazywała intuicja)
    porównywanie "idzie" od lewej do prawej w danym słowie.
Inne przypadki możesz sobie sam sprawdzić, o ile uważasz to za niezbędne.

Widać więc, że porównywanie działa analogicznie jak dla liczb. Wystarczy więc, że w swojej wersji sortowania zamiast porównywania liczb wstawisz analogiczne porównywanie stringów i powinno wszystko hulać.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 19 cze 2011, 12:09
autor: luzakwielki
fraktal pisze:Dojdziemy do tego metodą prób i błędów.
Ty serio metodą prób i błędów dochodziłeś do tego czy się zgrywasz? To chyba jasne, że małe litery są większe od dużych i wynika to z przyporządkowania znaków liczbą w ASCII (np. 'a' to 97, a 'A' to 65), jednak takie porównywanie można zastosować tylko jak się jest anglikiem, nie uznającym innych języków za dopuszczalne - np. polska litera 'ą' w kodowaniu ISO ma numer 177, a w Unicode 261, więc przy takim sortowaniu jak proponujesz będziesz miał 'ą' jako późniejszą w alfabecie niż 'z'.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 19 cze 2011, 12:27
autor: fraktal
Pewnie że żartowałem:)
Chciałem tylko pokazać, że nawet jak się nie ma odpowiednio dużej wiedzy, to można do pewnych rzeczy dojść właśnie poprzez próby, niekoniecznie czytając całą dokumentację. A że pomaga to w kreatywnym myśleniu to chyba tylko lepiej, prawda?

PS. Nie odrzucam w tym momencie gruntownej wiedzy na dany temat, taka też powinna być zdobywana.

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 20 cze 2011, 00:43
autor: Enkidu
Dzięki za wyjaśnienie o co chodzi z komparatorem ;)

Ostatnia prośba... Czy w tej funkcji jest błąd?

Kod: Zaznacz cały

void wczytaj(zawodnik *adres){
    ifstream file("baza.txt");
    if(file.good()){
          while(!file.eof()){
              file >> adres->imie >> adres->nazwisko >> adres->ranking;
              adres->nastepny = new zawodnik;
              adres = adres->nastepny;
              adres->nastepny = NULL;
          }
    }
    file.close();
}
Bo jak potem drukuje to, to drukuje mi dwa puste kolejne elementy :/

Re: [C++] jak zapisać dużą listę dynamiczną do pliku?

: 20 cze 2011, 14:48
autor: fraktal
To tworzenie elementu na samym końcu nie jest najrozsądniejszym wyjściem... Jak się znajdzie przed EOF-em znak biały to wczytajka wejdzie do pętli i utworzy pusty obiekt (mimo że nie powinna).

Spróbuj postąpić wg poniższego schematu, jak dla siebie coś pisałem to działało:
  • (to już w pętli po sprawdzeniu czy można wykonywać operacje na strumieniu)
    Utwórz obiekt
    Wczytaj dane
    Dołącz do listy
W ten sposób, gdy wczytasz ostatni element, nie utworzysz zbędnego elementu pustego.

Warto by też pomyśleć nad stworzeniem listy - klasy, stanowi to dobry trening programowania i jest dużo wygodniejsza w obsłudze (o ile się czujesz na siłach :)).