Variable erhöht sich um 2 statt 1



  • Hi.
    Ich habe neulich mit C++ angefangen und habe ein Wortratespiel geschrieben. Vom Prinzip her ist es wie Galgenmännchen, nur hat man unendlich viele versuche einen Buchstaben zu erraten. Am Ende wird dann eine Punktzahl auf Basis der gebrauchten Versuche errechnet. Die Anzahl der Versuche zähle ich mit dem Befehl ++Versuche;. Die Wörter sind dabei auf türkisch. Das einzige Problem das ich habe ist, dass die Variable 'versuche' um 2 erhöht wird wenn ich einen türkischen Buchstaben (ı, ğ, ş, ç) eingebe. Ansonsten immer um 1. Woran kann das liegen ? Ich habe das Spiel dabei am Handy geschrieben (cxxdroi) weil ich gerade in Urlaub bin.

    Mit freundlichen Grüßen



  • Ohne Code? Hm, meine Glaskugel sagt, die türkischen Zeichen sind UTF-8 Zeichen mit je 2 Byte und du zähltst char aka Byte.



  • @darkface348 sagte in Variable erhöht sich um 2 statt 1:

    ğ

    Das liegt daran, daß ğ zB ein UNICODE Code Point ist, der in utf-8 aus 2 Bytes besteht: 196 und 159. Sieht also für std::cin aus, wie zwei Zeichen.



  • @swordfish Kann es sein, dass du Unicode Code Points und Kodierung verwechselst? Die Repräsentation 196 159 ist UTF-8. In UTF-16 wäre es dagegen 0x01 0x1f (oder andersrum, je nach byte order). Der Codepoint für das ğ ist U+011F.



  • @wob ich hab schon utf-8 gemeint ... leider haben es meine finger beim Tippen ausgelassen.



  • Dieser Beitrag wurde gelöscht!


  • Ich dachte eigentlich, dass es überflüssig ist den Code zu posten, aber anscheinend ist es doch nötig.

    #include <iostream>
    #include <fstream>
    #include <string>
    #include </sdcard/CPP/Libraries/stdc++.h>
    #include <ctime>
    #include <cstdlib>
    #include <stdlib.h>
    using namespace std;
    
    
    int main(){
    // Erstelle Variablen
    int versuche = 0;
    int counter = 0; // Anzahl erratener Buchstaben
    string auswahl; // Das zu erratene Wort
    char input;
    
    // Bestimme Wort aus Liste
    srand(time(NULL));
    int rand();
    int loop = rand() % 100;
    
    // Lese Wort und wandle String in Char-Array um
    ifstream read;
    read.open("/storage/emulated/0/CPP/Eigene Projekte/Wörterraten/liste.txt");
    for (int z=0 ; z != loop; ++z){
    getline(read,auswahl);}
    int n = auswahl.length(); // Anzahl der Buchstaben des Wortes
    char richtig[n+1]; // Speichert bereits erratene Buchstaben
    char wort[n+1]; // array für das zu erratene Wort
    for(int x = 0; x != n; ++x){
    richtig[x] = '-';
    }
    strcpy(wort, auswahl.c_str());  
    
    // Zeigt an wie viele Buchstaben gesucht werde, welche
    // gefunden wurden und wie viele Versuche man bereits hatte
    input:
    for(int i = 0; i != n; ++i){
    cout << richtig[i];}
    cout << endl << "Denemeler: " << versuche << endl;
    cout << endl << "Bir harf yaz: " ;
    cin >> input;
    ++versuche;
    cout << "\033[2J\033[1;1H"; // Löscht alle ausgaben
    
    // Kontrolliert die Eingabe
    for(int f = 0; f != n; ++f){
    if(input == wort[f]){
    wort[f] = '-';
    ++counter; // zählt wie viele Buchstaben erraten wurden
    richtig[f] = input;}
    }
    
    if(counter == n){
    goto end;}
    goto input; // Bildet Schleife
    
    end: // Endergebis
    cout << "Aranan kelime: " << auswahl << endl;
    cout << "Denemeler: " << versuche << endl;
    cout << "Puan: " << (100 + n * 15) - (versuche - n) * 10;
    }
    

    Ich hoffe die Kommentare sind hilfreich.



    1. Rücke Deinen Code anständig ein!
    2. Vergiss goto und verwende Schleifen!

    #1 und 2 hab ich dir mal abgenommen, damit meine Antwort lesbar wird:

    #include <iostream>
    #include <fstream>
    #include <string>
    
    // #include </sdcard/CPP/Libraries/stdc++.h>
    // ^^ was ist das? weg damit!
    
    #include <ctime>
    #include <cstdlib>
    // #include <stdlib.h> Du inkludierst bereits <cstdlib>
    // die *.h-Header der C-Standardbibliothek sind in C++ nur aus Kompatibilitäts-
    // gründen dabei und afaik seit C++17 depreciated. Die Header der C Standard-
    // bibliothek heißen in C++ so wie in C, ihnen wird aber ein 'c' vorangestellt und
    // das ".h" am Ende entfällt. Beispiel: <time.h> --> <ctime>
    
    // Hier fehlt noch
    #include <cstring> // für strcpy(), das Du unten verwendest.
    
    using namespace std;
    
    int main() {
    	// Erstelle Variablen  <<-- bitte nicht das Offensichtliche kommentieren und
    	// Du "erstellst" nicht, sondern deklarierst, teilweise definierst.
    	int versuche = 0;
    	int counter = 0; // Anzahl erratener Buchstaben
    	string auswahl; // Das zu erratene Wort <<-- wieso heißt das Ding dann nicht
            // "zu_erratendes_wort"?
    	char input;
            // Generell gilt aber: Deklariere Variablen erst dort, wo sie gebraucht werden!
    
    	// Bestimme Wort aus Liste
    	srand(time(NULL)); // sollte Dir eigentlich eine Warnung Deines Compilers einhandeln.
            // Davon abgesehen gibt es für denn NULLZeiger in C++ schon seit längerem die Konstante nullptr
    
    	int rand(); // Was soll diese Deklaration von rand() hier?
            // rand() ist bereits in <cstdlib> deklariert. Weg damit!
    	int loop = rand() % 100; // Woher kommt die Hundert? Vermeide magic numbers im Code und
            // verwede stadtdessen Konstanten (const int anzahl_woerter = 100)
            // besser: Bestimme vorher programmatisch, wie viele Wörter in Deiner liste.txt vor-
            // handen sind.
    
    	// Lese Wort und wandle String in Char-Array um
    	ifstream read; // ein eindeutiger name wäre zB input_file
    	read.open("/storage/emulated/0/CPP/Eigene Projekte/Wörterraten/liste.txt");
            // ^^ spar Dir diese Zeile und verwende zum öffnen der Datei gleich den Konstruktor von 
            // ifstream:
            // ifstream read("/storage/emulated/0/CPP/Eigene Projekte/Wörterraten/liste.txt");
    
    	for (int z = 0; z != loop; ++z) {
    		getline(read, auswahl);
    	}
    
    	int n = auswahl.length(); // Anzahl der Buchstaben des Wortes
    
    	char richtig[n + 1]; // Speichert bereits erratene Buchstaben
    	char wort[n + 1]; // array für das zu erratene Wort
            // ^^ diese zwei Zeilen ... In C++ gibt es soetwas nicht. Arraygrößen müssen in C++ zur
            // Compile-Zeit feststehen und dürfen keine erst zur Runtime bekannten Werte sein.
            // Warum überhaupt Arrays of char und keine std::string s?
    
    	for (int x = 0; x != n; ++x) { // das Ergibt doch ein '-' zuviel in "richtig"? sollte es nicht
                                           // x < n heißen? ...........
    		richtig[x] = '-';
    	}
            // ........... und:
            richtig[n] = '\0'; // ???
    
    	strcpy(wort, auswahl.c_str());
    
    	// Zeigt an wie viele Buchstaben gesucht werde, welche
    	// gefunden wurden und wie viele Versuche man bereits hatte
    	do {
    		for (int i = 0; i != n; ++i) {
    			cout << richtig[i];
    		}
                    // da "richtig" jetzt Nullterminiert ist ... reicht statt obiger for-Schleife nicht
                    cout << richtig; // ???
    
    		cout << endl << "Denemeler: " << versuche << endl; // Du brauchst nicht für jeden
    		cout << endl << "Bir harf yaz: ";                  // Zeilenumbruch endl schreiben
                                                                       // '\n' bzw. "sonstwas\nwasanderes"
                                                                       // tuts auch.
    		cin >> input;
    		++versuche;
    		cout << "\033[2J\033[1;1H"; // Löscht alle ausgaben // das ist nicht portabel
    
    		// Kontrolliert die Eingabe
    		for (int f = 0; f != n; ++f) { // sollte wohl statt f != n besser f < n heißen
    			if (input == wort[f]) {
    				wort[f] = '-';
    				++counter; // zählt wie viele Buchstaben erraten wurden
    				richtig[f] = input;
    			}
    		}
    	} while (counter != n);
    
    	cout << "Aranan kelime: " << auswahl << endl;
    	cout << "Denemeler: " << versuche << endl;
    	cout << "Puan: " << (100 + n * 15) - (versuche - n) * 10; // kreativ ;)
    }
    
    1. Entscheide Dich bei Bezeichnern bitte für Deutsch *ODER* Englisch und verwende sprechende Variablenamen.


  • Das für dich wichtige ist noch, dass std::string ein Kodierungsagnostiker ist. Das heißt, dass Sonderzeichen je nach verwendeter Kodierung anders gespeichert werden können.

    Es gibt hier Alternativen wie zum Beispiel https://github.com/copperspice/cs_string, bei denen die Kodierung festgelegt ist. Dann funktioniert auch string.size() so, wie man sich das vorstellt.



  • @swordfish
    Ja das mit den Variablen ist mir auch aufgefallen und vielen Dank für die sonstigen Ratschläge und vor allem dafür, dass du den Code verbessert hast. Ich habe deine Notizen nur kurz überflogen, heute Abend schaue ich mir das genauer an.

    Ich verstehe aber immernoch nicht wirklich wie die türkischen Buchstaben dazu führen, dass '++versuche;' dazu führt, dass der Wert der Variable um 2 statt 1 erhöht wird. Selbst wenn 'cin' das als 2 Zeichen sieht, wie beeinflusst das den increment ? Wäre sehr dankbar wenn mir das jemand kurz erklären könnte.



  • Du gibst ğ ein, das in utf-8 aus den bytes (der einfachheit halber: chars) 196 und 159 besteht ...

    do {
            // ...
    	cin >> input; // 196 wird gelesen
    	++versuche;
            // ...
    } while (counter != n);
    

    schleife wiederholt sich:

    do {
            // ...
    	cin >> input; // 159 wird gelesen
    	++versuche;
            // ...
    } while (counter != n);
    

    versuche wurde zwei mal inkrementiert obwohl Du nur 1 Zeichen eingegeben hast.



  • @swordfish
    Oh mein Gott bin ich dumm. :smiling_face_with_open_mouth_cold_sweat:
    Jetzt hab ich's verstanden. Danke.