Zweidimensionales Array einlesen - Beenden durch Benutzereingabe



  • Hallo!

    Ich benötige Hilfe zu folgender Aufgabenstellung:
    Schreiben Sie ein Programm, das Tipps im Lotto 6 aus 45 verwaltet. Lesen Sie maximal 50 Tipps ein (ein Tipp besteht aus jeweils 6 Zahlen. Beenden der Eingabe mit 0) und danach das Ziehungsergebnis (ebenfalls 6 Zahlen). Geben Sie aus wieviele Sechser in den Tipps vorkommen.
    Anmerkung: Gehen Sie der Einfachheit halber davon aus, daß die einzelnen Zahlen in den Tipps und im Ziehungsergebnis aufsteigend sortiert eingegeben werden.

    Mein Lösungsansatz sieht bisher so aus:

    int main(){
        int tipps[50][6];
    
        cout << "Eingabe Tipps: ";
    
        for(int i = 0; i < 50; ++i){
            for(int j = 0; j < 6; ++j){
                cin >> tipps[i][j];
    
                if(tipps[i][j] == 0){
                    break;
    
                }
            }
        }
    
        return 0;
    

    }

    Durch die if-Anweisung kann ich nur die innere for - Schleife beenden. Leider ist mir nicht klar, wie ich beide for - Schleifen unterbrechen kann. Also ich suche nach einer Möglichkeit durch die Benutzereingabe 0 das Einlesen meines zweidimensionalen Arrays zu unterbrechen.

    Freue mich über jeden hilfreichen Tipp. Danke.


  • Mod

    Also ich suche nach einer Möglichkeit durch die Benutzereingabe 0 das Einlesen meines zweidimensionalen Arrays zu unterbrechen.

    Indem du die Abbruchbedingung der äußeren Schleife wahr werden lässt, i also größer-gleich 50 setzt.

    if (tipps[i][j] == 0)
    {
        i = 50;
        break;
    }
    

    Übrigens solltest du besser prüfen ob i nicht-gleich 50 ist, nicht kleiner 50 . Gleiches gilt für j und 6 .

    for (int i = 0; i != 50; ++i)
    


  • Vielen lieben Dank für die rasche Unterstützung.

    Eine Frage hätte ich noch bezüglich der for - Schleife:
    Ist es generell empfehlenswerter die Laufvariable mit ungleich größter Arrayindex zu vergleichen?
    Und falls ja, aus welchem Grund?


  • Mod

    Ist es generell empfehlenswerter die Laufvariable mit ungleich größter Arrayindex zu vergleichen?

    Ja - wenn du weißt dass sie ihm gleichen wird. Beispielsweise wenn du nur inkrementierst - dann kann sie ja nicht vorbeihopsen.

    Und falls ja, aus welchem Grund?

    Warum nicht? :p

    Zum einen ist's effizienter.

    Außerdem ist es auch konsequent im Bezug auf andere Abbruchbedingungen, wie bei Iteratoren-Schleifen:

    for (auto meinIterator = meinContainer.begin(); meinIterator != meinContainer.end(); ++iter)
    

    Iteratoren kannst du manchmal gar nicht mit < vergleichen, das können nämlich nur RandomAccess-Iteratoren. Alle anderen musst du per != vergleichen.



  • Verstehe. 🙂

    Danke


  • Mod

    Und natürlich solltest du auch prüfen ob der Einlese-Vorgang erfolgreich war.

    Der Ausdruck cin >> Tipps[i][j] zerfällt automatisch zu einem bool welcher false ist falls das Fehlerbit des Streams gesetzt wurde.
    ➡

    for (int i = 0; i != 50; ++i)
    		for (int j = 0; j != 6; ++j)
    			if (!(cin >> tipps[i][j]) || tipps[i][j] < 1 || tipps[i][j] > 49) // Bedingung verallgemeinert.
    			{
    				i = 50;
    				break;
    			}
    

    Es ist zudem garantiert dass der erste logische Ausdruck !(cin >> tipps[i][j]) vor dem zweiten und der vor dem dritten ausgeführt wird.



  • Ich habe das Befüllen meines zweidimensionalen Arrays ausprobiert.
    Wenn in meinen for - Schleifen (äußere for - Schleife < 50 bzw. innere for - Schleife < 6) schreibe, kann ich durch die Eingabe von 0 das Befüllen beenden und in weitere Folge die Elemente problemlos ausgeben.

    Jedoch wenn ich das Gleiche mit ungleich (äußere for - Schleife != 50 bzw. innere for - Schleife != 6) teste und 0 als Benutzer eingebe unterbricht es die Eingabe nicht.

    Verstehe nicht warum.



  • Um das zu verstehen, musst Du die for-Schleife ein wenig auseinandernehmen:

    // Der for Ausdruck
    for ( for-init-statement condition ; expression ) statement
    
    // ist equivalent zu:
    {
      for-init-statement
      while ( condition ) {
        statement
        expression ;
      }
    }
    

    D.h. die expression (bei Dir z.B. ++i ) wird zuletzt ausgeführt, bevor condition (bei Dir i!=50 ) erneut ausgewertet wird.
    Ist Dein statement jetzt i=50; , wird i anschließend inkrementiert - ist also 51 - und danach wird die Bedingung !=50 geprüft. Die ist jetzt wahr, also geht es weiter.

    Ich teile Arcoths Ansicht auch nicht in Zählschleifen mit != prüfen zu sollen.
    Wenn Du Dabei bleibst, muss Du i auf 49 setzen - das ist natürlich fast nicht mehr zu lesen, wenn Du in einer Woche auf den Code schaust... ("Huch! Warum jetzt 49? Wo kommt das her!?") 🙂



  • estrella schrieb:

    Leider ist mir nicht klar, wie ich beide for - Schleifen unterbrechen kann.

    for (...) {
      for (...) {
        if (...) {
          goto ende;
        }
      }
    }
    ende:
    

    Don't be afraid to use a goto if that is the best option.



  • Ich habe ein weiteres Problem mit der Befüllung eines zweidimensionalen Arrays. Dabei handelt es sich diesmal um ein char-Array.

    Die dazugehörige Aufgabenstellung lautet:
    Lesen Sie maximal 50 Zeichenketten ein (jede Zeichenkette hat maximal 80 Zeichen, Abschluß durch Eingabe von "Stop") sowie einen Wert n. Geben Sie dann alle Zeichenketten ein, die maximal n Zeichen lang sind. Die Verwendung von Stringfunktionen (strlen etc.) ist nicht gestattet.
    Anmerkung: Beachten Sie, dass beim Einlesen eine Zeichenkette durch ein Leerzeichen beendet wird. z.B.

    Eingabe: C++ ist ganz schön kompliziert so im Allgemeinen Stop n=4
    Ausgabe: C++ ist ganz so im

    Für mich stellt sich zu Beginn die Frage wie ich das Beenden durch die Benutzereingabe mit Stop am besten lösen kann.
    Dazu habe ich mir überlegt zwei Arrays anzulegen.

    char zeichenketten[50][81];
    char abschluss[] = "Stop";
    

    Beim Befüllen durch den Benutzer habe ich jetzt ein Problem, dass ich nicht in den Griff bekomme.
    Löse ich dies mit zwei ineinander verschachtelten for - Schleifen:

    cout << "Eingabe Zeichenketten: ";
    
        for(int i = 0; i < 50; ++i){
            for(int j = 0; j < 81 && zeichenketten[i][j] != '\0'; ++j){
                cin >> zeichenketten[i][j];
    
                if(zeichenketten[i][j] == abschluss[j]){
                    i = 50;
                    break;
    
                }
    
            }
    
        }
    

    endet das Befüllen unabhängig davon wie die letzte Eingabe lautet. Stimmt mein Ansatz generell nicht oder ist er für die Aufgabenstellung unpassend? Oder vielleicht könnte mir jemand bei der passenden Befüllung des Arrays helfen.

    Danke im Voraus



  • Tja Arcoth, da hast du dich mit deinem Tipp aber selber hereingelegt...

    Bei so etwas plädiere ich ganz einfach zur Auslagerung in eine eigene Funktion und 'return' dann aufzurufen!



  • @Furble Wurble
    Danke für die verständliche Erklärung. 🙂



  • estrella schrieb:

    char abschluss[] = "Stop";
    
    // ...
                
                if(zeichenketten[i][j] == abschluss[j]){
    

    Was passiert denn bei j > strlen(abschluss)?



  • Theoretisch sollte das abschließende Wort Stop nur aus 5 Zeichen (4 char und das Nullzeichen) bestehen, dadurch kann es nicht länger als 5 werden.

    Ich sehe jedoch das Problem, dass ich dabei nicht bedacht habe. Bin noch nicht sicher wie die Lösung dafür aussehen könnte.

    Wohl sollte ich zuerst herausfinden wie lange, also wie viele Zeichen, mein letztes Wort hat und falls es genau 5 Zeichen sind erst dann mit meinem Abschlusswort vergleichen.

    😕



  • Keine Ahnung, was das wieder soll...!?
    Was für ein Quatsch, auf C Strings rumzuhacken, anstatt irgendeine anspruchsvolle Aufgabe mit C++ zu erledigen...
    Schulaufgabe?

    Wie dem auch sei: ich würde erstmal zwei Funktionen schreiben.

    So ungefähr:

    // Bestimmt of s der String "Stop" ist
    bool is_stop(const char* s);
    
    // Bestimmt die Länge von s (ohne abschließende 0)
    int stringlen(const char* s);
    

    Damit im Gepäck sollte das doch alles ein Klacks sein. 😉



  • Th69 schrieb:

    Bei so etwas plädiere ich ganz einfach zur Auslagerung in eine eigene Funktion und 'return' dann aufzurufen!

    +1

    @Furble Wurble
    strlen, strcmp?

    @Arcoth

    for (int i = 0; i != 50; ++i)
            for (int j = 0; j != 6; ++j)
                if (...)
                {
                    i = 50;
                    break;
                }
    

    *schauder*
    =>

    int const tippCount = 50;
       for (int i = 0; i != tippCount; ++i)
            for (int j = 0; j != 6; ++j)
                if (...)
                {
                    i = tippCount;
                    break;
                }
    

    Dummerweise immer noch falsch.
    =>

    int const tippCount = 50;
       for (int i = 0; i != tippCount; ++i)
            for (int j = 0; j != 6; ++j)
                if (...)
                {
                    i = tippCount - 1; // ODER i < tippCount, wie "normale" Leute schreiben würden
                    break;
                }
    

    *schauder-schauder*
    Ach, was solls =>

    for (int i = 0; i != 50; ++i)
            for (int j = 0; j != 6; ++j)
                if (...)
                    return;
    

    Tadaaa


Anmelden zum Antworten