Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Textdatei in Array einlesen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
28.12.2015, 21:41 Uhr
~selina25042011
Gast


Hallo

ich bin Studentin im 1.Semester IT und für mich ist C++ noch eine recht neue Welt.

Ich habe eine Aufgabe zu Dateioperationen. Bei dieser soll ich Angaben von Schülern ( Nummer, Vorname, Nachname und Absolvierung der Prüfung ) in einer Struktur speichern.

Alle Daten der Schüler soll ich aus Textdatei die wie folgt aufgebaut ist einlesen und in einem Feld speichern. Um weitere Operationen mit diesen Daten durchführen zu können.

Code:
1    Torsten        Becker        0
2    Susanne             Mueller        1
3     Denise        Kowalski            1
4    Marko                Schmidt        0
5    Stefanie            Schaarschmidt    0
6    Andreas        Winter        1



Bis jetzt haben wir einfache Berechnungen, Schleifen, Felder, Strukturen und Funktionen behandelt. Und möchte auch gern mit diesen Wissen die Aufgabe lösen und nicht Dinge einbauen von denen ich noch keine Ahnung habe

Ich würde mich sehr über einer Denkanstoß freuen .... Bin schon ganz verzweifelt weil ich echt auf der Leitung stehe

Was ich bisher habe :

C++:
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>

using namespace std;

struct schueler
{     int nummer;
    string vorname;
    string nachname;
    bool pruef;
};

int main (void)
{    
    
    
    ifstream in ("schueler.txt");
    if (!in) cout << "konnte nicht geöffnet werden"<<endl;
    
    int i;
    for (i=0 ; i<6 ;i++)
    
    {  
     string line;
    getline (in,line);
    
    cout << line<<endl;
    

    }
    in.close();
    
    
    
    
    
    
    
    
    return 0;
}


Die Textdatei wird Zeile für Zeile ausgegeben, doch leider hängt es grad wie ich sie in ein Feld speichere und noch die Struktur mit einbeziehe

Würde mich sehr über einen kleinen Denkanstoß freuen.

Vielen lieben Dank schonmal im vorraus

-----
Edit: code- und cpp-Tags eingesetzt.

Dieser Post wurde am 28.12.2015 um 22:16 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
28.12.2015, 22:13 Uhr
Hans
Library Walker
(Operator)


Hi,

Du hast zwar eine Struktur deklariert, aber noch keine Variable angelegt, die diese Struktur enthält. Da fehlt also noch sowas wie

C++:
struct schueler
{ int nummer;
  string vorname;
  string nachname;
  bool pruef;
} S;   // hier wird noch einer Variable S vom Typ "struct schueler" erstellt


oder

C++:
int main()
{
  ...
  struct schueler S;
  ...
}


in dem Programm. Sieh Dir mal die Handhabung von struct in einem Buch oder Eurem Tutorial genauer an.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
28.12.2015, 22:36 Uhr
~selina25042011
Gast


vielen lieben dank für die schnelle antwort

ich hab dann auch gemerkt das ich dies noch vergessen habe ... danke


C++:

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>

using namespace std;

struct schueler
{     int nummer;
    string vorname;
    string nachname;
    bool pruef;
}daten;

int main (void)
{    
    
    
    ifstream in ("schueler.txt");
    if (!in) cout << "konnte nicht geöffnet werden"<<endl;
     int i;
    
    for (i=0 ; i<6 ;i++)
    
    {  
     in >> daten.nummer;
     in >> daten.vorname;
     in >> daten.nachname;
     in >> daten.pruef;
    
    string daten;
    getline (in,daten);
    cout<<daten<<endl;
    

    }
    in.close();
    
    
    
    
    
    
    
    
    
    
    return 0;
}




mein nächster Gedanke war dies doch leider habe ich noch meine Probleme beim einlesen mit Dateien. Und ich weis nicht wie ich das in Array packe.

Ich hat jezt an ein 2-dimensionales Feld gedacht von der Größe 6x4 .

Habe in meinen Büchern auch nicht viel gefunden.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
28.12.2015, 23:28 Uhr
~selina25042011
Gast


kleiner nachtrag da oben mein quellcode falsch ist


C++:

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>

using namespace std;

struct schueler
{     int nummer;
    string vorname;
    string nachname;
    bool pruef;
}daten;

int main (void)
{    
    
    
    ifstream in ("schueler.txt");
    if (!in) cout << "konnte nicht geöffnet werden"<<endl;
     int i;
    
    for (i=0 ; i<6 ;i++)
    
    {  
     in >> daten.nummer;
     cout << daten.nummer;
     in >> daten.vorname;
     cout << daten.vorname;
     in >> daten.nachname;
     cout << daten.nachname;
     in >> daten.pruef;
     cout << daten.pruef;
    
    
    string daten;
    getline (in,daten);
    cout<<daten<<endl;
    

    }
    in.close();
    
    
    
    
    
    
    
    
    
    
    return 0;
}




gut soweit bin ich bis jetzt gekommen.
-----
Edit: cpp-Endetag korrigiert; - Tags gehören in eckige Klammern.

Dieser Post wurde am 29.12.2015 um 22:34 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
30.12.2015, 01:03 Uhr
Hans
Library Walker
(Operator)


So, nachdem ich zweieinhalb Stunden zuvor das cpp-Tag korrigiert habe, hier nun das Feedback zum Programm: das läuft bei mir soweit. Es wäre aber noch sinnvoll, zwischen den einzelnen Elementen der Struktur Leerzeichen oder Tabulatoren auszugeben, sonst sieht die Ausgabe etwa so aus:

Code:
1TorstenBecker0
2SusanneMueller1
3DeniseKowalski1
4MarkoSchmidt0
5StefanieSchaarschmidt0
6AndreasWinter1



Die Fehlerabfrage macht man sinnigerweise besser so:

C++:
///////////////////////////////////////////////////////////////////////////////////////////////////
if (!in)
{ cout << "Datei schueler.txt konnte nicht geöffnet werden" << endl; // Wenn Datei nicht geöffnet
  exit(1);   // werden konnte, dann Programm nach Fehlermeldung abbrechen. - Sonst kann man sich
             // <cstdlib> auch sparen.
}  



Das hier:

C++:
    int i;
    for (i=0 ; i<6 ;i++)
      { ...                    


kann man auch so schreiben:

C++:
for (int i=0 ; i<6 ;i++)    
  { ...


Das ist in C++ eigentlich die übliche Form, sofern man nicht gerade von C (ohne ++) kommt, wo alle Variablen am Anfang deklariert werden müssen. Und solange Du den Wert von i nur innerhalb der Schleife brauchst, ist das auch völlig in Ordnung. Anders sieht es aus, wenn Du den Wert hinterher noch brauchst, etwa weil die Schleife vorzeitig abgebrochen wurde. Dann muss man i vorher deklarieren, damit man hinterher auch noch drauf zugreifen kann. Aber ich glaube, das würde in Deinem Fall gerade zu weit führen...

Ein wenig Schleierhaft sind mir diese Zeilen:

C++:
  string daten;
  getline (in,daten);
  cout << daten << endl;


Da definierst Du eine Stringvariable, die nur innerhalb der Schleife existiert. Aber, soweit ich das bisher sehe, legt getline nichts darin ab und die folgende cout-Zeile gibt nur endl aus. Wenn Du das also auf

C++:
  cout << endl;


eindampfst, funktioniert es immer noch.

Was das Array angeht, so reicht ein eindimensionales Array aus, da man auch Arrays von Strukturen definieren kann. In Deinem Fall wäre das etwa:

C++:
struct schueler
{   int nummer;
    string vorname;
    string nachname;
    bool pruef;
}daten[6]; // HIER die entscheidende Erweiterung, also Arraydefinition.



Der Zugriff auf die einzelnen Elemente erfolgt dann in der Schleife z.B. durch

C++:
  daten[i].nummer


usw. - Das kannst Du testen, indem Du zwei Schleifen hintereinander schreibst, wobei die erste die Daten liest und die zweite sie ausgibt.

Zuletzt noch:

Zitat von ~selina25042011:
Habe in meinen Büchern auch nicht viel gefunden.

Ah ja. Welche Bücher sind das?
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 30.12.2015 um 17:17 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
30.12.2015, 11:46 Uhr
ao

(Operator)



Zitat von Hans:

Ein wenig Schleierhaft sind mir diese Zeilen:

C++:
  string daten;
  getline (in,daten);
  cout << daten << endl;


Da definierst Du eine Stringvariable, die nur innerhalb der Schleife existiert. Aber, soweit ich das bisher sehe, legt getline nichts darin ab ...

getline (istream &, string &) tut das hier: Zeichen aus dem Stream lesen und in dem string ablegen, und zwar bis zum nächsten Zeilenende, wobei das Zeilenende selber weggeworfen und nicht in den String gelegt wird. Siehe hier: www.cplusplus.com/reference/string/string/getline/

Indem man mit dem String nichts weiter anfängt, drückt man hier aus, dass man alle benötigten Daten hat und dass der Rest der Zeile (falls es einen gibt) nicht interessiert.

In diesem konkreten Fall ist Rest leer, weil die in>>-Aufrufe schon alles ausgelesen haben. Das getline wird also nur aufgerufen wegen der "Nebenwirkung", das Zeilenende aus dem Stream zu entfernen, damit beim nächsten Schleifendurchlauf ein frischer Datensatz zur Verfügung steht.

Das muss aber nicht der Fall sein, die nächste Version der schueler.txt kann nach dem Prüfungs-Flag noch weitere Daten enthalten, die dann ignoriert werden. Es ist also gar nicht so doof, mit einem getline in eindeutiger und erweiterbarer Weise den nächsten Datensatz klarzumachen. Ein Kommentar könnte jedoch nicht schaden.

Problematisch an dem Code ist, dass die String-Variable ebenfalls "daten" heißt und damit die globale Variable struct schueler daten verdeckt. Auch das ist erst mal kein Fehler, kann aber den Programmierer verwirren, und gibt spätestens dann Probleme, wenn man zwischen dem getline und dem Ende der Schleife nochmal an die struct-Daten heranwill. Die sind da nämlich nicht erreichbar.

Und ich persönlich würde die Schleife so programmieren:

C++:
    for (i=0 ; i<6 ;i++)
    {  
        string s;            
        getline (in, s);    //    eine Zeile einlesen und zwischenspeichern
        
        stringstream ss (s);    //    Zeile in den stringstream laden

        ss >> daten.nummer;        //    stringstream feldweise ausquetschen
        cout << daten.nummer;
        ss >> daten.vorname;
        cout << daten.vorname;
        ss >> daten.nachname;
        cout << daten.nachname;
        ss >> daten.pruef;
        cout << daten.pruef;
                                          //    was jetzt noch im stringstream enthalten ist, wird verworfen.
        
        cout << endl;            //    Ausgabe formatieren
    }


Ich mag dieses fummelige Kleinklein auf Dateien nicht, ich habe lieber einen kompletten Datensatz im Speicher und nehme ihn da auseinander. Außerdem reflektiert der Code meiner Meinung nach deutlicher die Eigenschaft der Quelldaten, dass es sich um zeilenorientierte Datensätze handelt. Dass die Daten dabei öfter als unbedingt nötig umkopiert werden, nehme ich in Kauf. Aber das ist Geschmackssache.

Damit das so kompiliert, muss #include <sstream> vorangestellt werden., string

Dieser Post wurde am 30.12.2015 um 13:14 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
30.12.2015, 17:08 Uhr
Hans
Library Walker
(Operator)


Hi,

@ao:

Zitat von ao:

getline (istream &, string & ) tut das hier: Zeichen aus dem Stream lesen und in dem string ablegen, und zwar bis zum nächsten Zeilenende, wobei das Zeilenende selber weggeworfen und nicht in den String gelegt wird. Siehe hier: www.cplusplus.com/reference/string/string/getline/


Das hab ich auch schon heraus gefunden, da ich die Seite auch kenne. Und weil es in diesem Stream anscheinend kein Zeilenende-Kennzeichen gibt, bzw. dieses durch die in>>-Aufrufe schon verarbeitet wurde, hab ich ja geschrieben, das man es auch weglassen kann.


Zitat von ao:

Indem man mit dem String nichts weiter anfängt, drückt man hier aus, dass man alle benötigten Daten hat und dass der Rest der Zeile (falls es einen gibt) nicht interessiert.

In diesem konkreten Fall ist Rest leer, weil die in>>-Aufrufe schon alles ausgelesen haben. Das getline wird also nur aufgerufen wegen der "Nebenwirkung", das Zeilenende aus dem Stream zu entfernen, damit beim nächsten Schleifendurchlauf ein frischer Datensatz zur Verfügung steht.

Das muss aber nicht der Fall sein, die nächste Version der schueler.txt kann nach dem Prüfungs-Flag noch weitere Daten enthalten, die dann ignoriert werden. Es ist also gar nicht so doof, mit einem getline in eindeutiger und erweiterbarer Weise den nächsten Datensatz klarzumachen. Ein Kommentar könnte jedoch nicht schaden.


Da könnte ein Kommentar wirklich nicht schaden, denn da bin ich auch noch nicht drauf gekommen. Und ich glaube, diese Überlegung geht auch über Anfängerniveau hinaus.


Zitat von ao:

Problematisch an dem Code ist, dass die String-Variable ebenfalls "daten" heißt und damit die globale Variable struct schueler daten verdeckt. Auch das ist erst mal kein Fehler, kann aber den Programmierer verwirren, und gibt spätestens dann Probleme, wenn man zwischen dem getline und dem Ende der Schleife nochmal an die struct-Daten heranwill. Die sind da nämlich nicht erreichbar.


Das ist mir inzwischen auch aufgefallen. Das ist wohl ein Grund dafür, warum man Strukturen gerne so definiert:

C++:
struct SCHUELER
{   int nummer;
    string vorname;
    string nachname;
    bool pruef;
}schueler_daten;  // oder einfach nur "schueler" in Kleinbuchstaben


Dann hat die Struct-Variable einen eindeutigen Namen, der nicht so schnell zu Verwirrung führen kann.


Zitat von ao:

Ich mag dieses fummelige Kleinklein auf Dateien nicht, ich habe lieber einen kompletten Datensatz im Speicher und nehme ihn da auseinander.

Das hätte ich in C wahrscheinlich auch so gemacht, indem ich mit fread() einen kompletten Datensatz, bzw. eine komplette Zeile gelesen hätte, diese anschliessend zerlegt und die einzelnen Teile den Strukturelementen zugeweisen. Aber ich stelle gerade fest, dass das etwas mehr gefummel wäre, als in C++...

Bearbeitung:

Ich hab das jetzt mal in C gemacht und es war noch mehr gefummel als ich erwartet hatte. Hab aber fgets() anstelle von fread() genommen, weil ja Textzeilen verarbeitet werden und keine binären Daten vorkommen. Den entsprechenden Code erspare ich uns hier, - falls Interesse besteht, poste ich den vielleicht in einem anderen Thread, weil er hier OffTopic wird. (und ausserdem eine Lösung verrät, die die Fragestellerin sich erstmal selbst erarbeiten soll.)


Aber es stimmt natürlich, letzten Endes ist es Geschmacksache, wie man die Verarbeitung der Datensätze löst.

Hans


P.S.

Zitat von ao:

Damit das so kompiliert, muss #include <sstream> vorangestellt werden., string


Oh, was wurde denn hier verschluckt?
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 30.12.2015 um 22:37 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: