JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=deae7d60231ef77410188e746501a2b6Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Problem mit STL-Strings

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
valentin_
Mini JLI'ler


Alter: 34
Anmeldedatum: 16.07.2006
Beiträge: 28
Wohnort: Graz
Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 15:31    Titel: Problem mit STL-Strings Antworten mit Zitat

Hi.
Ich hab hier ein recht simples Programm, wo ich einfach nicht verstehe, weshalb es nicht so funktioniert, wie ich es will!!

Soll ein Adressbuch, oder soetwas in der Art werden.

Hier erst mal der Code:

CPP:
#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct Eintrag
{
   int Nummer;
   string Vorname;
   string Nachname;
};


void main(void)
{
   Eintrag Buffer;
   
   FILE *MainDatei = NULL;

   int Menu = 0;

   puts(" Adressbuch\n");

   printf("\n 1 ... Neuer Kontakt");
   printf("\n 2 ... Kontakte Anzeigen");
   printf("\n Waehle Aktion: ");
   cin >> Menu;

   switch(Menu)
   {
   case 1:
         MainDatei = fopen("d:\\Kontakt.bin","ab");
   
         printf("\n Nummer: ");
         cin >> Buffer.Nummer;
         getchar();

         printf(" Vorname: ");
         getline(cin,Buffer.Vorname);      
         getchar();

         printf(" Nachname: ");
         getline(cin,Buffer.Nachname);
         getchar();
                  
         printf("\n Neuer Kontakt: Nr.%d  Name: %s %s ",Buffer.Nummer,Buffer.Vorname.c_str(),Buffer.Nachname.c_str());
         
         fwrite(&Buffer,sizeof(Buffer),1,MainDatei);

         fclose(MainDatei);

         getchar();

      break;

   case 2:
         MainDatei = fopen("d:\\Kontakt.bin","rb");

         fread(&Buffer,sizeof(Buffer),1,MainDatei);

         printf("\n Kontakt: Nr.%d  Name: %s %s ",Buffer.Nummer,Buffer.Vorname.c_str(),Buffer.Nachname.c_str());

         fclose(MainDatei);

         getchar();

      break;

   }


   printf("\n\n Beenden mit <RET>\n");
   getchar();
}



Also.
Wenn ich die Daten einles funktioniert ja alles noch, aber wenn ich sie aus der Datei wieder auslesen möchte, werden anstelle der strings irgendwelche Zeichen ausgegeben. Weiß, aber nicht wieso?

Weiters würde ich gern wissen, ob man irgendwie in erfahrung bringen kann, wie viele Elemente eine Datei enthält. Denn ich weiß ja nicht, wie viele Kontakte in der Datei bereits vorhanden sind. Bei Textdatein lässt sich das mit while(!feof(Datei)) sehr elegant lösen. Was gibt es da für möglichkeiten bei Binärdateien??

Und als letztes hab ich noch ne Frage zu getline(). Zwar funktioniert es bei mir mit getchar() nach jeder eingabe, aber das ist etwas nervig. Fällt euch da etwas besseres ein?

Ich dank euch schon mal im vorraus für eure hilfreichen Antworten!!


valentin_
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 16:01    Titel: Antworten mit Zitat

Naja, dein Code ist etwas ulkig, du mixt munter alte C-Konstrukte wie FILE, fopen etc. mit neueren C++-Konstrukten. Ich denke du wirst sicher versehentlich die selbe Datei einmal als Textdatei und einmal als Binärdatei behandeln, daher werden deine Daten unterschiedlich interpretiert und der Murks mit den Zeichen entsteht, hab grade auch nicht die Lust mich da durch zufitzen. Am besten du haust den ganzen alten Mist von wegen fopen, fclose usw. raus, benutzt Streams, und streamst deine Einträge direkt in die Datei, geht easy, sauber und stabil mit wenigen Zeilen. ;)

Zuletzt bearbeitet von GreveN am 01.03.2007, 16:05, insgesamt einmal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Christian Rousselle
Site Admin


Alter: 48
Anmeldedatum: 19.07.2002
Beiträge: 1630

Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 16:05    Titel: Antworten mit Zitat

Das wird so nicht funktionieren, weil die Größe von string nicht das ist, was du meinst. Bei sizeof(std::string) bekommst du 32 - das ist die Größe der Daten, die eine String-Klasse nutzt, nicht jedoch die länge eines Strings.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 16:21    Titel: Antworten mit Zitat

Ich hab mal eben ein kleines Beispiel zusammen geschustert, müsste so funktionieren. ;)
Übrigens, du kannst natürlich auch direkt Daten von der Konsole in eine Datei streamen und umgekehrt, überhaupt lassen sich da noch jede Menge andere nette Dinge anstellen, aber ich hab's bewusst einfach gehalten... ;)

CPP:
#include <iostream>
#include <string>
#include <fstream>


struct eintrag
{
    unsigned int nummer;
    std::string vorname;
    std::string nachname;
};


int main()
{
    eintrag buf;

    std::cin >> buf.nummer;
    std::cin >> buf.vorname;
    std::cin >> buf.nachname;


    std::fstream out("test.dat", std::ios::binary | std::ios::out);

    out << buf.nummer;
    out << buf.vorname;
    out << std::endl;
    out << buf.nachname;

    out.close();



    std::fstream in("test.dat", std::ios::binary | std::ios::in);

    eintrag buf2;

    in >> buf2.nummer;
    in >> buf2.vorname;
    in >> buf2.nachname;

    std::cout << buf2.nummer << std::endl;
    std::cout << buf2.vorname << std::endl;
    std::cout << buf2.nachname << std::endl;

    return 0;
}
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
valentin_
Mini JLI'ler


Alter: 34
Anmeldedatum: 16.07.2006
Beiträge: 28
Wohnort: Graz
Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 16:48    Titel: Antworten mit Zitat

Danke erstmal.
Der Mix der verschiedenen Konstrukte entsteht halt, wenn man sich durch verschiedenste Interner-Tuts ackert. Very Happy

Hab zwar noch nie mit Streams gearbeitet, aber das werd ich schon hinbekommen!

valentin_
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 01.03.2007, 17:47    Titel: Antworten mit Zitat

Von wegen der Anzahl der Einträge: Schreib das einfach mit in die Datei.
Zum Beispiel könntest du alle Einträge in einem Array, einer Liste oder sonstwas speichern. Auf jeden Fall wirst du immer im Programm die Länge dieses Konstruktes erfahren können. Diese schreibst du einfach als Integer (kommt halt auf den maximal angepeilten Wert an, wie groß die Variable für die Datei sein muss, aber 32bit brauchen nicht viel Platz in der Datei und es passen schon sehr große Zahlen rein) an den Anfang der Datei.
Beim Laden lädst du erst diese Größe, und kannst dann in einer einfachen for-Schleife alle Einträge auslesen.

Natürlich geht auch in Binärdateien "eof" (müsste es ja bei jeglicher Art von Dateileseoperationen geben), aber geschickter ist halt, wenn das in der Datei drin steht.
Außerdem empfiehlt es sich eine Versionsnummer in die Datei zu schreiben. Wenn du das Dateiformat irgendwann mal ändern solltest, lässt du die alte Ladefunktion und schreibst eine neue und kannst an der Nummer gucken welche du nehemn muss (mit switch oder so).
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
valentin_
Mini JLI'ler


Alter: 34
Anmeldedatum: 16.07.2006
Beiträge: 28
Wohnort: Graz
Medaillen: Keine

BeitragVerfasst am: 04.03.2007, 18:29    Titel: Antworten mit Zitat

Ich schreibe jetzt die Anzahl der Einträge ans Anfang meiner Datei.
Nur weiß ich jetzt nicht, wie ich die Anzahl ändern soll, wenn eich einen neuen Eintrag mache.
Oder wenn ich einen Eintrag lösche möchte ich ja die jenige Zeile löschen, aber auch das gelingt mir nicht.

Mit Datei.seekp(...) kann man sich zwar bewegen, aber ich weiß nicht wie man Daten manipulieren kann.

valentin_
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 04.03.2007, 18:40    Titel: Antworten mit Zitat

an den Anfang der Datei kannst du den Stream mit s.seekp( 0, std::ios::beg ) setzen. Das klappt immer, und ist im Gegensatz zu s.seekp( 0 ) auch offset-sicher. Danach einfach ganz normal mit operator << oder s.put() o.Ä. weiter schreiben. Die Daten, die vorher an dieser Stelle standen, werden überschrieben. Beim Löschen also einfach auf deine Zeile gehen und mit einer neuen oder dem Dateiende etc. überschreiben-.

btw: du kannst mit seekp (auch bei seekg) noch andere Ausgangspositionen als 2. parameter angeben wie std::ios::end fürs Dateiende oder std::ios::cur(um vom jetzigen Standort aus zu verschieben) oder eben std::ios::beg für den Beginn. Der 1. Parameter gibt dazu den relativen abstand an. Um bspw. den Stream 5 Zeichen zurück zu bewegen, müsstest du seekp( -5, std::ios::cur ) machen.[/code]

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 04.03.2007, 18:43    Titel: Antworten mit Zitat

Öh, wenn du es wirklich so machen willst, dann einfach die Daten überschreiben. Schreibzeiger auf das Offset setzen und einen neuen Wert eintragen.

Einfach mitten in der (Binär)Datei etwas löschen geht nicht so einfach (zumindest kenn ich keine Methode), im Prinzip musst du die Daten, die hinter dem betroffenen Abschnitt liegen neu an das Offset des gelöschten Absatzes schreiben - ich hoffe ich laber hier nicht totalen Mist. ;) Also quasi den hinteren Teil vorrücken an das Ende des ersten Teils, aber dafür sind die überladenen Stream-Operatoren nicht unbedingt gedacht, in dem Fall bieten sich die write- und read-Methode des Streams eher an. Schön geht in den meisten Fällen auch das Arbeiten auf dem internen stream_buf-Objekt, was die eigentlichen Daten hält.

Achja, sehr smart gehen solche Operationen auch mit den Stream-Iteratoren und den Algorithmen aus der STL.

Am besten du durchstöberst mal die gängigen Referenzen, die Stream- und Pufferklassen sind eigentlich alle ziemlich intuitiv aufgebaut und ein tiefergehendes Verständnis schadet bekanntlich eigentlich ja nie... ;)
http://www.cplusplus.com/reference/iostream/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 04.03.2007, 20:25    Titel: Antworten mit Zitat

Ähm. Ich mache das immer so, dass ich die komplette Datei in den Hauptspeicher lade. Da kann ich dann mit den Daten machen was ich möchte. Zum speichern überschreibe ich einfach die gesamte Datei.
Das geht sehr viel einfacher, als bei jeder Veränderung die passende Stelle in der Datei zu finden und zu ersetzen.
Das einzige was IMHO dagegen spricht die Datei einmal komplett zu laden und dann einmal wieder komplett zu überschreiben wäre, wenn diese sehr sehr groß ist. So 500 mb oder so, halt dass es mit der Hauptspeichergröße Probleme geben könnte.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 04.03.2007, 20:59    Titel: Antworten mit Zitat

Ja, im Prinzip funktioniert es ja auch mit den Streams von Haus aus so. Wenn du bestimmte Bereiche zum "Löschen" überschreibst, arbeitest du im Normalfall ja auch immer auf irgendwelchen Puffern - wie eben z.B. den filebuf-Objekten. Ich hatte ja schonmal angedeutet, dass man schön mit den streambuf- bzw. filebuf-Objekten arbeiten kann... die halten im Prinzip auch den kompletten Inhalt der Datei bzw. des Ein-/Ausgabe-Objektes, welches dem Stream zugrunde liegt und werden nur hin und wieder mit dem jeweiligen "physischen Ende" des Stroms, also der eigentlichen Datei/Konsole/... synchronisiert... std::endl macht das zum Beispiel, einfach weil das ganze Drumherum um das Speichern/Anzeigen/... das Ganze sonst zu unperformant machen würde.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum