Zahlen aus Array vergleichen



  • Schleifenvariablen wie i oder j im Schleifenkopf deklarieren, system calls sind nicht gerade empfehlenswert (lahm, sicherheitslücken, vermutlich nicht portabel, ...), wenn man nur einen Zeilenumbruch will: '\n'

    #include <array>
    #include <iostream>
    #include <limits>
    
    int main() {
        using namespace std;
    
        array<int, 6> userzahl;   // int userzahl[6], aber "besser"
        for(unsigned i=0; i<userzahl.size(); i++) {
            // fand das übersichtlicher, auch zum debuggen
            cout<<"\n Bitte geben sie die " << i+1 << ". Zahl ein: ";
            cin>>userzahl[i];
            while(userzahl[i] < 1 || userzahl[i] > 46){
                    cout<<"\n Unguelitge Eingabe\n";
                    cout<<"\n Bitte neue Zahl eingeben:\n";
                    cin>>userzahl[i];
            }
            for(unsigned j=0;j<i;j++){
                while (userzahl[i]==userzahl[j]){
                        cout<<"\n Zahl bereits Voranden!";
                        cout<<"\n Bitte neue Zahl eingeben: ";
                        cin>>userzahl[i];
                }
            }
        }
    
        cout<<"\nIhre Zahlen: ";
        //for (unsigned i = 0; i < userzahl.size(); ++i)
            //cout << userzahl[i] << ' ';
        for (const auto& n : userzahl)
            cout << n << ' ';
        // system("Pause");
        // ist ehrlich gesagt bei Übungsprogrammen auch egal...
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cin.get();
    }
    

    P.S.: Ich hab an der eigentlich Logik nichts verändert (ich kann deinen Fehler nicht reproduzieren)
    ~edit: Compiler könnte meckern wegen vergleich unsigned mit signed (korrigiert), das if do while kann man zu while vereinfachen~;



  • HarteWare schrieb:

    Das erklärt das Buch aber hoffentlich nicht, dass man die Schleifenvariablen wie i oder j schon davor deklarieren soll, oder dass system calls empfehlenswert sind, oder dass man endl nehmen soll, wenn man nen Zeilenumbruch will:

    #include <array>
    #include <iostream>
    #include <limits>
    
    int main() {
        using namespace std;
    
        array<int, 6> userzahl;   // int userzahl[6], aber "besser"
        for(unsigned i=0; i<userzahl.size(); i++) {
            // fand das übersichtlicher, auch zum debuggen
            cout<<"\n Bitte geben sie die " << i+1 << ". Zahl ein: ";
            cin>>userzahl[i];
            while(userzahl[i] < 1 || userzahl[i] > 46){
                    cout<<"\n Unguelitge Eingabe\n";
                    cout<<"\n Bitte neue Zahl eingeben:\n";
                    cin>>userzahl[i];
            }
            for(unsigned j=0;j<i;j++){
                while (userzahl[i]==userzahl[j]){
                        cout<<"\n Zahl bereits Voranden!";
                        cout<<"\n Bitte neue Zahl eingeben: ";
                        cin>>userzahl[i];
                }
            }
        }
    
        cout<<"\nIhre Zahlen: ";
        //for (unsigned i = 0; i < userzahl.size(); ++i)
            //cout << userzahl[i] << ' ';
        for (const auto& n : userzahl)
            cout << n << ' ';
        // system("Pause");
        // ist ehrlich gesagt bei Übungsprogrammen auch egal...
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cin.get();
    }
    

    P.S.: Ich hab an der eigentlich Logik nichts verändert (ich kann deinen Fehler nicht reproduzieren)
    ~edit: Compiler könnte meckern wegen vergleich unsigned mit signed (korrigiert), das if do while kann man zu while vereinfachen~

    Hi HarteWare

    Danke für die Antwort.
    Ich habe ein teil vom Code aus einem einem C-Code genommen den ich zuvor geschreiben habe bevor ich mich entschied dann doch direkt mit C++ anzufangen darum ist der System Call noch dadrin, aber endl wird durch alle 900 Seiten des Buches benutzt. Die Schleifenvariable wird auch immer zuvor definiert.

    Interpretier ich das richtig und kann so allgemein verwendet werden?

    array<int, 6> userzahl;
    array<datentyp, Anzahl> Variablennamen;
    Bsp:
    array<char, 8> Text;
    

    Und diesen Teil verstehe ich noch nicht so ganz;

    cout<<"\nIhre Zahlen: ";
        //for (unsigned i = 0; i < userzahl.size(); ++i)
            //cout << userzahl[i] << ' ';
        for (const auto& n : userzahl)
            cout << n << ' ';
        // system("Pause");
        // ist ehrlich gesagt bei Übungsprogrammen auch egal...
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cin.get();
    

    Gruss Thomas



  • Hallo Thomas,

    BlackNeon schrieb:

    for(j=0;j<i;j++){
    				if(userzahl[i]==userzahl[j]){
    					do{
    						cout<<"\n Zahl bereits Voranden!";
    						cout<<"\n Bitte neue Zahl eingeben: ";
    						cin>>userzahl[i];
    					}while (userzahl[i]==userzahl[j]);
    				}
    			}
    

    dieser Code ist funktional falsch. Wenn Du bereits zwei Zahlen eingegeben hast, so kannst Du die zweite Zahl nochmal eingeben .. die wird zwar nicht übernommen, aber Du landest in obiger do-while-Schleife und anschließend kannst Du die erste Zahl noch einmal eingeben.
    Probier's mal aus.

    Die tiefere Ursache dieses Fehlers liegt in der Redundanz der Eingabe in den Zeilen 8, 14 und 22 (s. Originalposting).

    Versuche den Code so zu ändern, dass das Einlesen der Zahl nur an einer einzigen Stelle im Programm vorkommt.
    IMHO resultieren 90% aller Programmierfehler aus Redundanzen und impliziten Annahmen.

    Gruß
    Werner



  • Hi Werner,

    Danke für die Antwort.

    Werner Salomon schrieb:

    dieser Code ist funktional falsch. Wenn Du bereits zwei Zahlen eingegeben hast, so kannst Du die zweite Zahl nochmal eingeben .. die wird zwar nicht übernommen, aber Du landest in obiger do-while-Schleife und anschließend kannst Du die erste Zahl noch einmal eingeben.
    Probier's mal aus.

    Hast recht das funktioniert wirklich. 🙂

    Werner Salomon schrieb:

    Versuche den Code so zu ändern, dass das Einlesen der Zahl nur an einer einzigen Stelle im Programm vorkommt.

    Für einen blutigen Anfänger ist das einfacher gesagt als getan 😉 aber ich geb mein bestets eine Lösung zu finden, ansonsten meld ich mich später wieder, wenn mein Kopf raucht und ich noch keine Lösung hab.



  • BlackNeon schrieb:

    Hi Werner,

    Danke für die Antwort.

    Werner Salomon schrieb:

    dieser Code ist funktional falsch. Wenn Du bereits zwei Zahlen eingegeben hast, so kannst Du die zweite Zahl nochmal eingeben .. die wird zwar nicht übernommen, aber Du landest in obiger do-while-Schleife und anschließend kannst Du die erste Zahl noch einmal eingeben.
    Probier's mal aus.

    Hast recht das funktioniert wirklich. 🙂

    Werner Salomon schrieb:

    Versuche den Code so zu ändern, dass das Einlesen der Zahl nur an einer einzigen Stelle im Programm vorkommt.

    Für einen blutigen Anfänger ist das einfacher gesagt als getan 😉 aber ich geb mein bestets eine Lösung zu finden, ansonsten meld ich mich später wieder, wenn mein Kopf raucht und ich noch keine Lösung hab.

    So die Köpfe sind am rauchen, hab mich mit einem Mitarbeiter zusammengesetzt und das versucht zu lösen. Die einzige Möglichkeit die wir gefunden besteht darin es mit Funktionen zu lösen aber, da ich nicht gerade viel Ahnung davon hab wie das richtig funktioniert, fällt dies auch weg. Ich/Wir währen um einen Tipp oder einen Lösungsanzsatz froh, wenn möglich im Spaghetticode (Ohne Funktionen und Verweise).

    Danke und Gruss

    Thomas



  • Wie wäre es damit, für die Überprüfung ob eine Zahl bereits vorhanden ist einfach ein Set zu nehmen, dann kann man sich die Aufwändige Schleife sparen und die Zahlen sind gleich sortiert, was bei Lottozahlen ja durchaus sinnvoll ist:

    #include <iostream>
    #include <set> 
    using namespace std; 
    
    const int AnzahlZahlen = 6;
    
    bool valueinvalid(int value) {
      return  userzahl[i] < 1 || userzahl[i] > 46;
    }
    
    int main() { 
        set<int> Zahlen
            for(int i=0; i<AnzahlZahlen; i++) { 
                cout<<"\n Bitte geben sie eine Zahl ein: "; 
                int userzahl;
                for (cin>>userzahl; valueinvalid(userzahl); cin>>userzahl;) {
                        cout<<"\n Unguelitge Eingabe"<<endl; 
                        cout<<"\n Bitte neue Zahl eingeben: "<<endl; 
                }
                auto ret = Zahlen.emplace(userzahl)
                for(;!ret.second;cin>>userzahl,Zahlen.emplace(userzahl)) {
                            cout<<"\n Zahl bereits Voranden!"; 
                            cout<<"\n Bitte neue Zahl eingeben: "; 
                    } 
                } 
            } 
        cout<<"\n Ihre Zahlen:";
        for (const auto& n : userzahl)
        cout << n << ' ';
    }
    

    Wenn es unbedingt ein Array sein muss würde ich zumindest einen Algorithmus für die Überprüfung auf doppelte Zahlen nehmen.



  • Hallo Thomas,

    BlackNeon schrieb:

    Werner Salomon schrieb:

    Versuche den Code so zu ändern, dass das Einlesen der Zahl nur an einer einzigen Stelle im Programm vorkommt.

    So die Köpfe sind am rauchen, hab mich mit einem Mitarbeiter zusammengesetzt und das versucht zu lösen. Die einzige Möglichkeit die wir gefunden besteht darin es mit Funktionen zu lösen aber, da ich nicht gerade viel Ahnung davon hab wie das richtig funktioniert, fällt dies auch weg. Ich/Wir währen um einen Tipp oder einen Lösungsanzsatz froh, wenn möglich im Spaghetticode (Ohne Funktionen und Verweise).

    Ja, ja - ein scheinbares einfache Problem; und doch so schwierig!

    Nehmen wir mal an Du überlegst, wie es in Deinem Programm ab Zeile 7 weiter geht. Dort soll eine Zahl eingegeben und geprüft werden. Bei negativem Prüfergebnis soll die Eingabe wiederholt werden.
    Beginne wie folgt:

    for(;;)  // forever, bis Eingabe ok (s.u.)
            {
                cout << "\n Bitte geben sie eine Zahl ein: ";
                cin >> userzahl[i];
                // und hier kommt jetzt die Prüfung; falls alles ok, wird die Schleife mit 'break;' verlassen
            }
    

    Zuerst die Prüfung, ob die Zahl im Intervall von 1 bis 46 liegt:

    const int MINI = 1;
        const int MAXI = 46;    // Konstanten vermeiden die Redundanz von Zahlen
        const int N = 6;
    
        int userzahl[N];
        for (int i = 0; i < N; ++i) {
            for(;;)  // forever, bis Eingabe ok (s.u.)
            {
                cout << "\n Bitte geben sie eine Zahl ein: ";
                cin >> userzahl[i];
                if( MINI <= userzahl[i] && userzahl[i] <= MAXI ) // prüfe ob die Zahl im geforderten Intervall liegt
                {   // die Zahl liegt im Intervall
    
                    // ... ggf. weitere Prüfungen
    
                    break; // Schleife verlassen, Eingabe ist ok
                }
                else
                {   // die Zahl liegt nicht im Intervall
                    cout << " Ungueltige Eingabe - Zahl liegt nicht im geforderten Intervall [" << MINI << ".." << MAXI << "]" << endl;
                }
            }
    

    Anschließend kann man jetzt die zweite Prüfung einbauen. Also überprüfen, ob die Eingabe doppelt ist. Verständlicher Weise muss die Zahl jetzt mit jeder der bereits eingegebenen verglichen werden. Dazu benutze ich eine for- Schleife. Wenn die for- Schleife verlassen wird, muss klar sein, ob eine gleiche Zahl gefunden wurde. Das erreiche ich, indem ich den Laufindex auf das Ende prüfe (also hier ==i ) - dann wurde keine gleiche Zahl gefunden.

    for(;;)  // forever, bis Eingabe ok (s.u.)
            {
                cout << "\n Bitte geben sie eine Zahl ein: ";
                cin >> userzahl[i];
                if( MINI <= userzahl[i] && userzahl[i] <= MAXI ) // prüfe ob die Zahl im geforderten Intervall liegt
                {   // die Zahl liegt im Intervall
                    int j = 0; // 'j' erst hier, aber außerhalb der for-Schleife in der nächste Zeile deklarieren, da der Index später noch gebraucht wird
                    for( ; j < i; ++j )
                    {
                        if( userzahl[i] == userzahl[j] )
                            break;  // einfach abbrechen; 'j' wird nicht weiter erhöht und ist demnach !=i
                    }
                    if( j == i )    // Ende erreicht; keine Zahl war gleich
                        break;      // Schleife verlassen, Eingabe ist ok
                    cout << " Zahl bereits vorhanden!" << endl;
                }
                else
                {   // die Zahl liegt nicht im Intervall
                    cout << " Ungueltige Eingabe - Zahl liegt nicht im geforderten Intervall [" << MINI << ".." << MAXI << "]" << endl;
                }
            }
    

    Gruß
    Werner



  • Wenn du mal gross bist, lernst du solche Programme zu schreiben:

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <boost/algorithm/clamp.hpp>
    #include <boost/range/algorithm/count.hpp>
    #include <boost/iterator/filter_iterator.hpp>
    
    int main()
    {
      std::vector<int> userzahl;
      std::copy_n(boost::make_filter_iterator([&](int i){
            return (i==boost::algorithm::clamp(i, 1, 46) && !boost::range::count(userzahl, i)) || !(std::cout << "Ungueltige Eingabe\n"); },
          std::istream_iterator<int>(std::cin)),
        6,
        std::back_inserter(userzahl));
    }
    


  • Bin leider nicht so der Boost-Experte aber schwer beeindruckt. Wie wäre es als Herausforderung mit der kompaktesten Lösung mit C++ Bordmitteln?



  • Die Schwierigkeit ist, die Abbruchbedingung zu setzen. Bei copy_if braucht es dann als Hack, std::cin in einen Fehlerstatus zu setzen, damit die Eingabe stoppt:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <iterator>
    
    int main()
    {
      std::vector<int> userzahl;
      std::copy_if(std::istream_iterator<int>(std::cin), std::istream_iterator<int>{}, std::back_inserter(userzahl), [&](int i) {
                     if (userzahl.size() == 6) return std::cin.setstate(std::ios_base::failbit), false;
                     return (1<=i && i<=46 && std::count(userzahl.begin(), userzahl.end(), i)) || !(std::cout << "Ungueltige Eingabe\n"); });
      std::cin.clear();
    }
    


  • Hallo zusammen

    Danke für die Antworten, die ich leider erst jetzt gelesen habe und doch schon eine Lösung gefunden habe dank eines Denkanstosses unseres Progress-Programmierers, der mir gezeigt hat wie er das ganze im Progress geschreiben hat.
    Vor 10min habe ich das Lottospiel noch ganz fertig geschrieben und wollte euch noch meine Lösung vorstellen, inklusive Auswertung, Zahlengenerator und Resultat. Die ganzen Kommentare im Code waren für das Debugging, lasst euch davon nicht iritieren. Der Code ist wahrscheinlich viel zulange für das was ich machen wollte aber jeder fängt mal klein bzw. in diesem Fall mit nem grossen Code an 😉

    #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <time.h>
    using namespace std;
    
    int zahleneingabe();
    
    int main() {
    	int userzahl[6] = {0, 0, 0, 0, 0, 0};
    	int genzahl[6] = {0, 0, 0, 0, 0, 0};
    	int neuezahl, neuegen, i, j, resultat=0;
    	const int x=1,y=46;
    	for(i=0; i<6; i++){
    		neuezahl=zahleneingabe();
    		//cout<<"neuezahl: "<<neuezahl;
    		if(neuezahl < 1 || neuezahl > 46){
    			cout<<"\n Zahl ungueltig!\n";//<<i;
    			i--;
    		}
    		else{
    			//cout<<"else";
    			for(j=-1;j<i;j++){
    				//cout<<"neu: "<<neuezahl;
    				if(userzahl[j]==neuezahl){
    					cout<<"\n Zahl schon vorhanden!\n";//<<userzahl[j]<<" : "<<neuezahl<<"    "<<" j: "<<j<<"  i: "<<i;
    					i--;	
    				}else{
    					userzahl[i] = neuezahl;
    				}
    			}
    		}
    	}
    	cout<<"\n Ihre Zahlen:  "<<userzahl[0]<<" "<<userzahl[1]<<" "<<userzahl[2]<<" "<<userzahl[3]<<" "<<userzahl[4]<<" "<<userzahl[5]<<endl;
    	//cout<<"\n Lottozahlen werden erzeugt!\n";
    	srand((unsigned)time(NULL));
    	for(int k=0; k<6; k++){
    		genzahl[k] = (rand()%46);
    		genzahl[k]++;
    		for(int l=0; l<k; l++){
    			if(genzahl[k]==genzahl[l]){
    				k--;
    			}
    		}
    	}
    	cout<<"\n Lottozahlen:  "<<genzahl[0]<<" "<<genzahl[1]<<" "<<genzahl[2]<<" "<<genzahl[3]<<" "<<genzahl[4]<<" "<<genzahl[5]<<"\n";
    
    	//cout<<"\n Zahlen werden verglichen";
    
    	for(int m=0;m<6;m++){
    		for(int n=0;n<6;n++){
    			if(genzahl[m]==userzahl[n]){
    				resultat++;
    			}
    		}
    	}
    
    	//cout<<"\n Resultat wird ausgegeben";
    	if(resultat==0){
    		cout<<"\n Sie haben "<<resultat<<" von 6 Zahlen richtig! Sorry, versuch es nocheinmal!\n\n";
    	}else{
    	cout<<"\n Sie haben "<<resultat<<" von 6 Zahlen richtig! Glueckwunsch!\n\n";
    	}
    
    	cin.get();	
    	return 0;
    
    }
    
    int zahleneingabe(){
    	int neuezahl;
    	cout<<"\n Bitte Zahl eingeben: ";
    	cin>>neuezahl;
    	return neuezahl;
    }
    

    Irgendwann vieleicht einmal 😉 Noch verstehe ich deinen Code nicht.

    cpppro schrieb:

    Wenn du mal gross bist, lernst du solche Programme zu schreiben:

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <boost/algorithm/clamp.hpp>
    #include <boost/range/algorithm/count.hpp>
    #include <boost/iterator/filter_iterator.hpp>
    
    int main()
    {
      std::vector<int> userzahl;
      std::copy_n(boost::make_filter_iterator([&](int i){
            return (i==boost::algorithm::clamp(i, 1, 46) && !boost::range::count(userzahl, i)) || !(std::cout << "Ungueltige Eingabe\n"); },
          std::istream_iterator<int>(std::cin)),
        6,
        std::back_inserter(userzahl));
    }
    

    Ja wir haben Stunden damit verbracht bis wir auf eine Lösung gekommen sind um genau zusein 1,5 Arbeitstage. Naja aber nur so lernt man. Danke für deine ausfürhliche Antwort ich werde mir davon noch Notizen machen und noch in meinen Code einbinden so gut es geht.

    Werner Salomon schrieb:

    Ja, ja - ein scheinbares einfache Problem; und doch so schwierig!

    Nehmen wir mal an Du überlegst, wie es in Deinem Programm ab Zeile 7 weiter geht. Dort soll eine Zahl eingegeben und geprüft werden. Bei negativem Prüfergebnis soll die Eingabe wiederholt werden.
    Beginne wie folgt:

    for(;;)  // forever, bis Eingabe ok (s.u.)
            {
                cout << "\n Bitte geben sie eine Zahl ein: ";
                cin >> userzahl[i];
                // und hier kommt jetzt die Prüfung; falls alles ok, wird die Schleife mit 'break;' verlassen
            }
    

    Zuerst die Prüfung, ob die Zahl im Intervall von 1 bis 46 liegt:

    const int MINI = 1;
        const int MAXI = 46;    // Konstanten vermeiden die Redundanz von Zahlen
        const int N = 6;
    
        int userzahl[N];
        for (int i = 0; i < N; ++i) {
            for(;;)  // forever, bis Eingabe ok (s.u.)
            {
                cout << "\n Bitte geben sie eine Zahl ein: ";
                cin >> userzahl[i];
                if( MINI <= userzahl[i] && userzahl[i] <= MAXI ) // prüfe ob die Zahl im geforderten Intervall liegt
                {   // die Zahl liegt im Intervall
    
                    // ... ggf. weitere Prüfungen
    
                    break; // Schleife verlassen, Eingabe ist ok
                }
                else
                {   // die Zahl liegt nicht im Intervall
                    cout << " Ungueltige Eingabe - Zahl liegt nicht im geforderten Intervall [" << MINI << ".." << MAXI << "]" << endl;
                }
            }
    

    Der "set" befehl ist mir noch unbekannt und konnte den Code nur teilweise verstehen. Aber trotzdem Danke 🙂

    TNA schrieb:

    Wie wäre es damit, für die Überprüfung ob eine Zahl bereits vorhanden ist einfach ein Set zu nehmen, dann kann man sich die Aufwändige Schleife sparen und die Zahlen sind gleich sortiert, was bei Lottozahlen ja durchaus sinnvoll ist.

    Ihr könnt nach Lust und Laune meinen Code noch in Fetzen reissen und Verbesserunsvorschläge bringen. Wie gesagt man lernt ja nie aus 🙂

    Nochmals Danke für all die Hilfe 👍

    Gruss Thomas


Anmelden zum Antworten