Brauche Hilfe bei nicht funktionierender while Schleife



  • Hallo zusammen!

    Ich will ein Programm schreiben, das mir die Anzahl der einzelnen Buchstaben in einem Text zählt.
    Allerdings bleibt die Anzahl der Zeichen immer 0, da die while-Schleife zum Zählen der Buchstaben nicht ausgeführt wird, ich habe aber keine Ahnung warum nicht.

    Hier ist der Code:

    int main()
    {

    int loop[7];

    ifstream dat_ein;
    string dateiname;
    char zeichen;
    long zaehler = 0;
    char buchstabe;

    cout << " Gib den Namen der Datei ein: " << endl;
    cin >> dateiname;
    cout << endl << endl;

    cout << " Der Text der Ausgangsdatei lautet: " << endl << endl;

    dat_ein.open(dateiname.c_str(), ios_base::in);

    if(!dat_ein)
    {
    cout << "Datei konnte nicht geoefnet werden." << endl;
    cout << " Beachte bitte die Infos zur Benutzung dieses Programmes" << endl;

    return -1;
    }

    while(!dat_ein.eof()) // Die Schleife funktioniert !!!
    {
    dat_ein.get(buchstabe);
    cout << buchstabe;
    }

    cout << endl << endl << endl;
    cout << "---------------------------------------------" ;
    cout << endl << endl << endl;

    cout << "Vorkommen der einzelnen Zeichen: " ;
    cout << endl << endl << endl;

    // Vorkommen der einzelnen Zeichen zählen

    zeichen = 'a';

    for(loop[7]=0; loop[7] <= 26; ++loop[7])
    {

    while (!dat_ein.eof()) // Hier steckt glaub ich der Fehler!?
    {
    dat_ein.get(buchstabe);

    if (zeichen == buchstabe)
    ++ zaehler;
    }

    cout << "Das Zeichen " << zeichen << " kommt in dem Text ";
    cout << zaehler << " Mal vor." << endl;

    zeichen++ ;
    zaehler = 0;

    ...

    Kann mir jemand helfen?
    Vielen Dank schon mal im Voraus! 🙂



  • das eof failbit wird in der ersten while-schleife gesetzt und ergo ist es beim anfang der 2. dann immer noch da.

    Ich habe leider gerade vergessen wie man die fehlbits zurücksetzt, gabs da etwas wie mit reset? (im Zweifelsfall: schlieszen und wieder öffnen geht auch, hehe. Aber den Befehl findest du bestimmt, vllt auf www.cppreference.com)

    (akari, wo war der Link für das Syntaxcoloring?)

    Naja, egal, du hast unter deinem beitrag beim erstellen einen Button wo C/C++ draufsteht. Bitte rahme deinen Code damit ein dann liest es sich besser.



  • Joo schrieb:

    Allerdings bleibt die Anzahl der Zeichen immer 0, da die while-Schleife zum Zählen der Buchstaben nicht ausgeführt wird, ich habe aber keine Ahnung warum nicht.

    ich schätze mal,dass du vergessen hast, die Variable mit

    ++var;
    

    in der while-Schleife zu packen.
    Aber mach mal den Code mit CodeTags, sieht ja grauenvoll aus -.-

    Edit:
    Du kannst das mit reset oder so zurücksetzen, kA



  • Also, eines schonmal vorweg, statt "cout << endl << endl << endl;" kannst du doch auch "cout << "\n\n\n"; schreiben. Ist kürzer.

    Ich glaube es liegt daran, dass du 2 While schleifen hast die auf das gleiche reagieren sollen. Wenn die 2 starten soll wenn die erste abgeschlossen ist, dann mach doch einfach vor die 2. While schleife eine Variable die um 1 erhöht wird, und dann bei der 2. Whilke schleife einfach noch "&&variable==1" hinzufügen.

    Hoffe es hilft.

    MFG: DerLateinProfi



  • Hallo,

    in C++ würde man solch einen Code einfach anders schreiben. Ich behaupte nicht, die einzige Wahrheit gepachtet zu haben aber ein typischer Code könnte folgendermaßen aussehen:

    // main.cpp
    
    #include <fstream>
    #include <string>
    #include <iterator>
    #include <map>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        // Wieso kompliziert, wenn's einfach geht? Datei einlesen in einer Zeile.
        string content(istreambuf_iterator<char>(ifstream("./test.txt")), istreambuf_iterator<char>());
        cout << content << endl;
    
        // ... und zum Zählen der Zeichen verwenden wir ne Map.
        typedef map<char, unsigned int> char_map_t;
        char_map_t char_count;
    
        for (string::const_iterator i = content.begin(); i != content.end(); ++i)
            ++char_count[*i];
    
        for (char_map_t::const_iterator i = char_count.begin(); i != char_count.end(); ++i)
            cout << i->first << '\t' << i->second << endl;
    }
    

    /EDIT: Zu kompliziert gedacht.



  • Schande über mich, es war nicht reset sondern clear...

    also schreibe zwischen die 2 while-Schleifen einfach mal dat_ein.clear(), ich denke dann sollte es gehen (oder ein neuer Fehler auftreten, wie das so üblich ist, hehe)

    EDIT: der Code von Konrad ist natürlich besser, könnte u.U. aber noch zu kompliziert sein (falls man den algorithm Header und die Standardcontainer noch nicht kennt)



  • int loop[7]; /* 0 ... 6 */
    
    for(loop[7]=0; loop[7] <= 26; ++loop[7])
    {
    

    Du rufst den Index-Operator auf, der dir an dieser Stelle eine Exception bringen sollte. Der Index eines Arrays beginnt bei 0 .. davon abgesehen ist der Rest des Quellcodes auch rel. sinfrei.



  • Joo schrieb:

    while (!dat_ein.eof()) // Hier steckt glaub ich der Fehler!?
    {
    dat_ein.get(buchstabe);
    if (zeichen == buchstabe)
    ++ zaehler;
    }

    * Die Semantik ist eine andere als man denkt
    * Der Code enthält eine potentielle Endlosschleife
    * Der Code ist nicht fehler-sicher.
    * Abhängig von der konkreten Leseoperation wird die Schleife selbst im Idealfall einmal zu oft betreten
    (zit nach HumeSikkins C++ FAQ zum Thema "Was man bei eof beachten muss"



  • Hallo zusammen!

    Also erst einmal Vielen Dank an alle, die versucht haben mir zu helfen!

    Eigentlich wollte ich jetzt schreiben:... und dann hat es auch geklappt.
    Leider muss ich nach viel Kopfzerbrechen zugeben, dass keiner der Tipps mir geholfen hat. 😕

    -dat_ein.clear() hat schlicht nichts verändert
    -Konrad Rudolfs Code habe ich einfach nicht verstanden
    -bei LPP1991´s Idee wurde die Schleife entweder nur einmal oder unentlich oft
    ausgeführt.

    Dann habe ich versucht diese Endlosschleife mit einer break-Bedingung abzubrechen, das hat aber auch nicht funktioniert(vielleicht lag´s auch an
    eof() der Link dazu hat mich aber nicht weitergebracht).

    naja, ich hab die Code-Passage noch mal ein
    (jetzt auch als richtigen Code 🙂 )

    while(!dat_ein.eof())
                           {
                             dat_ein.get(buchstabe);
                             cout << buchstabe;
                           }
    
                           ...                       
    
                           zeichen = 'a';
    
                           dat_ein.clear();
    
                           for(loop[7]=0; loop[7] <= 26; ++loop[7]) //loop[1-6] in ...                       {
    
                                while (!dat_ein.eof(), versuch==1)
                                {
    
                                  dat_ein.get(buchstabe2);
    
                                  if (zeichen == buchstabe2)
                                      ++ zaehler;
    
                                 if (dat_ein.eof())
                                     break;
    
                             }
    
                           cout << "Das Zeichen " << zeichen << " kommt in dem Text ";
                           cout << zaehler << " Mal vor." << endl;
    
                           zeichen++ ;
                           zaehler = 0;
    
                           }
    

    weiß irgendwer weiter?



  • Für den Fall, dass der Typ char 8 Bit belegt, ist das vielleicht eine Möglichkeit, die dem beabsichtigten Zweck nahekommt:

    #include<string>
    #include<cstdlib> // für exit( )
    #include<fstream>
    #include<iostream>
    
    using namespace std;
    
    int main() {
        // Definieren der Eingangsdatei
        string quelldateiname;
        cout << "Quelldatei? ";
        cin >> quelldateiname;
    
        // Datei öffnen:
        ifstream quelle;            // Datentyp für Eingabestrom 
        quelle.open(quelldateiname.c_str(), ios::binary|ios::in);
        if (!quelle) {   // Fehlerabfrage
            cerr << quelldateiname
                 << " kann nicht geöffnet werden!\n";
            exit(-1);
        }
        /* Bei einem char zu 8 Bits (nicht zwingend, aber üblich und
           hier vorausgesetzt) gibt es 256 Möglichkeiten.
           Die ersten 128 (0..127) entsprechen dem ASCII-Code.
           Je nach System kann der Typ char einem 
           unsigned char (-128..127)  oder einem
           signed char (0..255)  entsprechen.
         */
        int zaehler[256];
        for(size_t i = 0; i < 256; ++i) {
           zaehler[i] = 0;         // initialisieren
        }
    
        char ch;
        bool istUnsigned = false;
        while (quelle.get(ch)) { // Datei char-weise einlesen 
           int position = (int)ch;      
           if(position < 0) { // aha! unsigned char
              istUnsigned = true;
              position += 256;
           }
           // Zähler hochzählen
           ++zaehler[position];
        }
        quelle.close();
        // Alle gelesenen Zeichen mit Häufigkeit ausgeben, sofern sie
        // laut ASCII als "druckbar" gelten (Wert >=32):
        for(int i = 32; i < 256; ++i) {
           if(zaehler[i] > 0) {  // nicht-vorhandene ignorieren
              if(istUnsigned && i > 128) {
                 cout << (char)(i - 256);
              }
              else {
                 cout << (char)i;
              }
              cout << '\t' << zaehler[i] << endl;
           }
        }
    }
    

    Ganz ohne Map, um möglichst wenig vorauszusetzen. Allerdings hängt es vom jeweiligen System ab, ob char als unsigned oder signed interpretiert wird, was das Programm etwas komplizierter macht. Wenn es nur um BUCHSTABEN gehen soll, können diese mit der Abfrage

    if(zeichen >= 'A' && zeichen <= 'Z'
      || zeichen >= 'a' && zeichen <= 'z') {
    ...
    

    herausgefiltert werden (es gibt auch das Makro isalpha dafür).
    Die Filterwirkung gilt nur für ASCII-Zeichen, nicht für andere Zeichen/Zeichensätze!



  • Hallo,

    Vielen Dank für die Antwort! 😉
    Komme gerade aus dem Urlaub zurück und werde es gleich mal ausprobieren,
    bin sehr zuversichtlich. 🙂
    Danke auch dafür, dass Du den Code so geschrieben hast,
    dass ich ihn verstehen kann.

    Nochmals: Danke, Danke, Danke!


Anmelden zum Antworten