putch() Fehler beim Einlesen?



  • Hallo,

    ich möchte ein Programm mit einer typischen Passwortabfrage schreiben, hab allerdings ein Problem. Das Programm soll die einzelnen Buchstaben mit Hilfe von getch() in die Variable e_passwort[30] abspeichern und die Buchstaben per putch() als "*" auf dem Bildschirm ausgeben. Am Ende vergleiche ich das Soll-Passwort mit dem Ist-Passwort, das Ergebnis stimmt nicht überein obwohl das richtige PW eingegeben wurde. Als Test hab ich das eingegebene PW mit printf("") ausgegeben und siehe da, nach dem eingegebenem PW folgen so komische Zeichen.

    1.) Wo liegt der Fehler?
    2.) Wird die "ENTER" Taste auch noch mit gespeichert?
    3.) Wie löse ich das Problem?

    MFG Artem

    Hier der Code:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main()
    {
        char zeichen;
        char passwort[] = "hallo", e_passwort[30];                  //Deklaration Soll-Passwort und Ist-Passwort.
        int x=0;                                                    //Deklaration für die Anzahl der Arrays in e_passwort[] z.B. e_passwort[x].
    
        printf("Passwortabfrage: ");                                //Menueueberschrift.
    
        zeichen = getch();                                          //Zeicheneingabe.
        while(zeichen != 0x0D)                                      //wenn Zeichen ungleich "Enter".
        {
            if(zeichen != 0x08)                                     //wenn Zeichen ungleich "Bachspace".
            {
                e_passwort[x] = zeichen;
                putch('*');                                         //Die Zeichen als "*" auf dem Bildschirm ausgeben.
                x++;
            }
            else if(zeichen == 0x08 && sizeof(e_passwort) > 0)      //Wenn Zeichen genau gleich "Backspace" und Die Länge des String größer 0 ist.
            {
                e_passwort[sizeof(e_passwort) - 1];
                putch(0x08);                                        //putch(Backspace).
                putch(' ');                                         //Zeichen mit "Leerzeichen" ersetzen.
                putch(0x08);                                        //putch(Backspace).
            }
            zeichen = getch();
        }
        printf("\n%s",e_passwort);                                  //Testausgabe um die Fehlerursache zu ermitteln. Die Ausgabe liefert das eingegebene PW und darauf folgende kryptische Zeichen.
    
        if(e_passwort == passwort)                                  //wenn das Eingegebene Passwort genau gleich Soll-Passwort, dann...
        {
            printf("\nZugang gewaehrt...\n");
        }
        else                                                        //Ansonsten...
        {
            printf("\nFalsches Passwort!\n");
        }
    
        system("pause");                                            //Programm Pause
        return 0;                                                   //Rückgabe 0
    }
    


  • Weist du was in C ein String ist?
    Sicher nicht. Und trotzdem hackst du einfach mal drauf los.

    Strings vergleich man in C nicht mit == sondern mit der Funktion strcmp.
    Strings haben in C immer ein endendes '\0', das fehlt bei dir ebenso.
    getch()/putch() ist kein Standard.
    Für backspace nimmt man \b und nicht 0x08.
    Für newline nimmt man \n und nicht 0x0A.
    Für cr nimmt man \r und nicht 0x0D.
    Du gebrauchst sizeof falsch. Dafür gibt es strlen(), du begreifst den Sinn von sizeof nicht.
    ...



  • völlig ungetestet, weil ich kein getch() habe.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <conio.h>//hab ich nicht
    
    int main()
    {
        char passwort[] = "hallo";
        char e_passwort[30];
        int e_anzahl=0;//fand ich netter als x
    
        printf("Passwortabfrage: ");
    
    	for(;;){
    		char zeichen=getch();
    		if(zeichen==0x0d)
    			break;
    		else if(zeichen==0x08){
    			if(e_anzahl>0){
    				--e_anzahl;
    				putch(0x08);
    				putch(' ');
    				putch(0x08);
    			}
    		}
    		else{
    //edit: ups, vergessen if(e_anzahl<sizeof(e_passwort+-of_by_one_error))
    			putch('*');
    			e_passwort[e_anzahl]=zeichen;
    			++e_anzahl;
    		}
    	}
    	e_passwort[e_anzahl]='\0';//wichtig, die stringfunktionen erwarten nullterminierte strings
    
        printf("\n");
        printf("e_passwort: %s\n",e_passwort);
    
        if(strcmp(e_passwort,passwort)==0)//so vergleicht man strings
        {
            printf("\nZugang gewaehrt...\n");
        }
        else                                                        //Ansonsten...
        {
            printf("\nFalsches Passwort!\n");
        }
    
        return 0;                                                   //Rückgabe 0
    }
    


  • Bin kein hauptberuflicher EDV'ler. Ich bin noch ein Greenhorn.

    sizeof() = sagt mir die Größe der Variable in Bytes
    strlen() = Die Anzahl der Zeichen ohne \0

    Stimmt ich hab die Beiden verwechselt.
    Ich hab die "\0" jetzt eingefügt. Der Passwortvergleich funktioniert nun danke.

    Allerdings muss ich noch die Korrekturfunktion richten.

    MfG

    Edit: Hab nochmal mein Übungsbuch aufgeschlagen, konnte den Konflikt endlich beheben 🙄 Übung macht den Meister.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main()
    {
        char zeichen;
        char passwort[] = "hallo", e_passwort[30];                          //Deklaration Soll-Passwort und Ist-Passwort.
        int x=0;                                                            //Deklaration für die Anzahl der Arrays in e_passwort[] z.B. e_passwort[x].
    
        printf("Passwortabfrage: ");                                        //Menueueberschrift.
    
        zeichen = getch();                                                  //Zeicheneingabe.
        while(zeichen != '\r')                                              //wenn Zeichen ungleich "Enter".
        {
            if(zeichen != '\b')                                             //wenn Zeichen ungleich "Backspace".
            {
                e_passwort[x] = zeichen;
                putch('*');                                                 //Die Zeichen als "*" auf dem Bildschirm ausgeben.
                x++;
            }
            else if((zeichen == '\b') && (strlen(e_passwort) > 0))          //Wenn Zeichen genau gleich "Backspace" und Die Länge des String größer 0 ist.
            {
                e_passwort[x-1] = '\0';
                putch('\b');
                putch(' ');
                putch('\b');
                x--;
            }
            zeichen = getch();
        }
        e_passwort[x] = '\0';
    
        if(strcmp(e_passwort, passwort) == 0 && (strlen(e_passwort) <= 5))  //wenn das Eingegebene Passwort genau gleich Soll-Passwort, dann...
        {
            printf("\nZugang gewaehrt...\n");
        }
        else                                                                //Ansonsten...
        {
            printf("\nFalsches Passwort!\n");
        }
    
        system("pause");                                                    //Programm Pause.
        return 0;                                                           //Rückgabe 0.
    }
    


  • strlen ist ein Stringfunktion. Die braucht einen nullterminierten String, damit sie richtig funktioniert.

    In deiner while -Schleife hast du das aber gar nicht.

    Allerdings hast du mit x ja schon die Anzahl der Zeichen.

    Das e_passwort[x - 2]; hat übrigens keinen Effekt.



  • Die "Binäre 0" ist jetzt in der Schleife gesetzt. Das Löschen und das Vergleichen funktioniert nun endlich.

    MfG


  • Mod

    Artem90 schrieb:

    "Binäre 0"

    Deine Vorstellungen über Zahlen im Computer ist ein bisschen komisch.



  • Das wichtigste zuerst:
    Du überprüfst nirgends die Länge der Eingabe.
    Der Nutzer könnte beliebig lange Passwörter eingeben.
    Könnte, weil vorher sicher das Programm/System abstürzt.

    Beide strlen in deinem Code sind überflüssig.

    In der Schleife kennst du die Länge durch x und ein String ist genau dann gleich, wenn auch die Länge übereinstimmt.( "hallo" und "hallo!" sind unterschiedlich).

    Bei der Schleife bietet sich auch ein do-while an.



  • Ich hab jetzt den Quelltext etwas geändert, ich hoffe das ich den Pointer richtig gesetzt habe. Die Variable "x" hab ich komplett entfernt und das ganze in eine Schleife verpackt.

    Der Compiler bringt nur folgende Warnung: "comparison between pointer und integer [enabled by default]". Das Programm funktioniert aber.

    Deine Vorstellungen über Zahlen im Computer ist ein bisschen komisch.

    \0 = Nullbyte und
    \0 = Binäre 0 laut dem Buch "C programmieren von Anfang an von Helmut Erlenkötter".

    MfG

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main()
    {
        char passwort[13] = "hallo";                                    //Passwort.
        char *zeichen;                                                  //Pointer auf zeichen.
        char e_passwort[13];                                            //Passworteingabe.
        int versuche = 1;
    
        printf("Passwortabfrage:\n");
        printf("\nSie haben 3 Versuche (max. 12 Zeichen).\n");
    
        while(strcmp(e_passwort, passwort) != 0 && versuche <= 3)       //Schleife für 3 Versuche.
        {
            printf("\n%i.) Versuch: ", versuche);
    
            e_passwort[0] = '\0';
    
            zeichen = getch();
    
            while(zeichen != '\r')
            {
                if(zeichen != '\b' && strlen(e_passwort) <= 11)         //Wenn zeichen ungleich "Backspace" und Zeichenlänge größer oder gleich 11, dann...
                {
                    strcat(e_passwort, &zeichen);                       //Eingegebenes Zeichen an das e_passwort hinten anhängen.
                    printf("*");
                }
    
                else if(zeichen == '\b' && strlen(e_passwort) > 0)      //Wenn zeichen genau gleich "Backspace" und Zeichenlänge größer 0, dann...
                {
                    e_passwort[strlen(e_passwort) - 1] = '\0';          //"Nullbyte" um 1 zurück verschieben.
                    printf(" \b\b \b");
                }
    
                else if(strlen(e_passwort) > 12)                        //Wenn Zeichenlänge größer als 11, dann...
                {
                    e_passwort[strlen(e_passwort) - 1] = '\0';          //"Nullbyte" um 1 zurück verschieben.
                    printf("\b*\b");
                }
                zeichen = getch();
            }
    
            versuche++;                                                 //Versuche +1.
        }
    
        if(strcmp(e_passwort, passwort) == 0)                           //Wenn das Passwort genau gleich ist wie das eingegebene Passwort, dann...
        {
            printf("\nZugang gewaehrt...\n");
        }
    
        else                                                            //Ansonsten...
        {
            printf("\nFalsches Passwort!\n");
        }
    
        system("pause");
        return 0;
    }
    


  • Weswegen ist zeichen ein Zeiger?



  • Weswegen ist zeichen ein Zeiger?

    Wenn ich den Zeiger nicht mache, dann stürzt das Programm ab.

    also wenn

    char zeichen;
    strcat(e_passwort, zeichen);
    dann kommt ein Programmabsturz.

    und

    char zeichen;
    strcat(e_passwort, &zeichen);
    dann fügt strcat() nach jedem Eintippen ein "hallo" dahinter, also das eigentliche PW (was unter der Variable char passwort[] gespeichert ist).

    bei

    *char zeichen;
    strcat(e_passwort, &zeichen);
    funktioniert das Ganze.

    Irgendetwas hab ich übersehen, denn Folgendes funktioniert auch:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main()
    {
        char zeichen;
        char text[20];
    
        text[0] = '\0';
    
        zeichen = getch();
        while(zeichen != '\r' && (strlen(text) <= 18))
        {
            strcat(text, &zeichen);
            printf("*");
            zeichen = getch();
        }
        printf("\n%s",text);
    }
    


  • Artem90 schrieb:

    Weswegen ist zeichen ein Zeiger?

    Wenn ich den Zeiger nicht mache, dann stürzt das Programm ab.

    Mal wieder ein Beweis, dass Compiler-Warnings und -Fehler nie beachtet werden, sondern einfach die Fehler durch wahlloses hinzufügen von Sternen und Ampersand unterdrückt werden, auch wenn sie komplett das Verhalten verändern.

    Artem90 schrieb:

    char zeichen;
    strcat(e_passwort, zeichen);
    dann kommt ein Programmabsturz.

    Ja, weil strcat nur C-Strings (also char*) miteinander verknüpfen kann, nicht einzelne Chars. strcat ist also die falsche Funktion für dein Vorhaben. Aber du ignorierst den Compiler, der dir das sagt, und fügst einfach wild Zeichen ein, um das Programm in einen kompilierfähigen, aber falschen Zustand zu bringen.



  • strcat erwartet zwei Zeiger auf nullterminierte Zeichenketten (sog. C-Strings).

    Das zweite Argument erfüllt diese Bedingung aber nur durch Zufall. (die Nullterminierung fehlt)

    Du kannst zeichen als Array definieren

    char zeichen[2] = {'\0', '\0'};
    

    Wenn du dann das Zeichen haben willst (beim getch und beim Vergleich), nimmst du das erste Element (zeichen[0]).
    Bei strcat das ganze Array (zeichen)
    Das ist aber nicht C-Style.

    Noch was:

    DirkB schrieb:

    Du überprüfst nirgends die Länge der Eingabe.
    Der Nutzer könnte beliebig lange Passwörter eingeben.
    Könnte, weil vorher sicher das Programm/System abstürzt.

    Bei der (inneren) Schleife bietet sich auch ein do-while an.



  • Zum Anhängen eines einzelnen Zeichens an einen String verwendet man strncat

    enum{PSIZE=20};
    
    int main()
    {
    char zeichen;
    char text[PSIZE+1]="";
    int i;
    
    for(i=0;i<PSIZE&&(zeichen=getch(),zeichen!='\r');++i)
      strncat(text, &zeichen, 1),
      printf("*");
    printf("\n%s",text);
    return 0;
    }
    

    oder direkt beschreiben ohne strncat

    int main()
    {
    char zeichen;
    char text[PSIZE+1]="";
    int i;
    
    for(i=0;i<PSIZE&&(text[i]=getch(),text[i]!='\r');++i)
      printf("*");
    printf("\n%s",strtok(text,"\r"));
    return 0;
    }
    


  • Danke für die Hilfe, die Funktionen sind mir noch nicht bekannt. Ich werde mich erstmal mit dem gepestetem Code befassen, um diesen erstmal zu verstehen.

    MfG



  • Artem90 schrieb:

    ..., die Funktionen sind mir noch nicht bekannt.

    So viele Funktionen hat die C-Standardlibrary nun auch nicht, dass man da nicht mal durschauen kann: http://en.cppreference.com/w/c

    Besonders nicht bei den Strings: http://en.cppreference.com/w/c/string/byte


Anmelden zum Antworten