Menü soll sich wiederholen, aber wie?



  • Guten Tag euch allen!

    Wie Ihr vllt sehen könnt, bin ich hier ganz neu dabei. Da ihr alle so aktiv seid, habe ich mir gedacht"werde auch du ein teil dieser community". ich weiß ich bin ein neuling hier aber mit der zeit bin ich iwann kein neuling mehr(logisch).
    jetzt zu der frage(ich habe suchfunktion benutzt aber nichts gefunden 😕 )

    ALSO: ich will ein programm schreiben dass mir die dezimal-zahlen in das oktale zahlensystem umwandelt und umgekehrt. nun ja dafür brauch ich zuerst ein menü dass mich wählen lässt ob ich "von dez in okt" oder "von okt in dez" oder "abbrechen" will. also 3 möglichkeiten sind im menü gegeben. das hab ich auch hingekriegt. ich will aber, dass mein menü am ende wieder erscheint, nachdem ich zb. von dez in okt gerechnet habe. einen ansatz habe ich natürlich schon gemacht:

    #include <stdio.h>
    main()
    {
    	int m;
    	do{
    	printf("				MENUE AUSWAHL\n");
    	printf("			      DRUECKEN SIE 1-3.\n");
    	printf(" 		****************************************\n");
    	printf("		*[1]Fuer Konvertierung Dezimal -> Oktal*\n");
    	printf("		*[2]Fuer Konvertierung Oktal -> Dezimal*\n");
    	printf("		*[3]	|----->ABBRUCH<-----|	       *\n");
    	printf(" 		****************************************\n");
    	printf("		Bitte Druecken Sie eine Zahl von  1 bis 3\n		bestaetigen Sie Ihre Wahl mit RETURN: ");	
    	scanf_s("%d",&m);
    	//Auswahlmenue ist fertig! Muss aber nach konvertieren wieder erscheinen!
    	//UPDATE: menü erscheint jetzt nach konertieren wieder. Jedoch kommt menü immer wieder wenn man buchstabe eingibt!
    ...
    ...
    ...
    	}while(m!=3);
    
    }
    

    Das problem ist hier, wenn ich statt eine Zahl einen buchstaben eingebe, dass mein menü unendlich mal wiedergegeben wird ohne dass ich iwas machen kann.
    ich glaube man kann das nicht mit einer einfachen do-while-schleife lösen.
    also wie krieg ich das hin? 😞
    naja ich hoffe ihr könnt einen anfänger weiterhelfen 😃 😃

    ich danke euch jetzt schonmal für die zeit die ihr aufgebracht habt um das hier überhaupt zu lesen 👍

    schönen tag noch Teschk



  • Statt mit scanf_s einen int einzulesen besser getchar() ein char lesen, und dann das uninterpretierte char auswerten mit c == '1', c=='2' usw.;
    switch/case bietet sich hier zur Auswertung an.



  • Wutz schrieb:

    Statt mit scanf_s einen int einzulesen besser getchar() ein char lesen, und dann das uninterpretierte char auswerten mit c == '1', c=='2' usw.;
    switch/case bietet sich hier zur Auswertung an.

    hey danke erstmal für deine hilfe!
    das mit "uninerpretierte char auswerten mit c=='1' usw" versteh ich nicht so genau, du meinst wahrscheinlich dass ich statt"int m", "char c;" hinschreibe? und dann statt scanf_s, c=getchar() hinschreibe? das problem hier ist, dass getchar() die eingabetaste mitliest 😞
    das mit switch/case habe ich jetzt gemacht und sieht auch gut aus aber dafür taucht das menü nicht wieder auf wenn ich eine konvertierung durchgeführt habe...

    gruß teschk



  • Au Backe ... mit Windows als Entwicklungsplattform? Ich habe mich damals ein Jahr mit abgequält, bevor ich das mal unter Linux ausprobiert habe - beste Entscheidung in dem Jahr.

    Also:

    1. Du schreibst int main(void) für den Funktionskopf. int bezeichnet den Rückgabecodetyp deiner Anwendung (damit eine andere Anwendung, die dein Programm aufruft, weiß, ob dein Programm jetzt erfolgreich war oder nicht). Das void gibt an, dass du keine Parameter erwartest.

    1. scanf_s ist nicht portable. getchar wurde ja schon vorgestellt.

    3. Wenn du Probleme mit den Umlauten auf deiner Konsole hast - das liegt daran, weil MS keine einheitlichen Zeichensätze zwischen "normalen Programmen" und der Kommandozeile verwendet. Normale Programme, wie dein Editor, in dem du deinen Code schrreibst, werden mit Codepage 1252 gespeichert. Die Kommandozeile verwendet aber ... 85x, irgendwas. Wusste ich mal auswendig.

    Wichtig ist nur das:

    #include <locale.h>
    
    int main(void)
    {
        /*Kann noch keine Umlaute*/
        printf("ÄäÖöÜöß\n");
    
        /*Jetzt sagen wir, dass die Standardcodepage verwendet werden soll.*/
        setlocale(LC_CTYPE,"ACP");
    
        /*Und jetzt sollten Umlaute auf einmal gehen.*/
        printf("ÄäÖöÜöß\n");
    }
    

    Zumindest hat das seinerzeit bei mir funktioniert.

    4. Hier mal so insgesamt mein Verbesserungsvorschlag:

    #include <stdio.h>
    #ifdef WIN32
    #include <locale.h>
    #endif
    
    void clear_input_stream(char c)
    {
    	while(getchar()!=c);
    }
    
    int main(void)
    {
    	/*Wichtig: wir speichern den Input als unsigned char - also ohne
    	**Vorzeichen. D.h. wir haben keine negativen Werte hier.*/
    	unsigned char input;
    
    	/*Wir wollen den Zeichensatz nur auf Windows-Plattformen ändern.*/
    #ifdef WIN32
    	setlocale(LC_CTYPE,"ACP");
    #endif
    
    	do
    	{
    		/*Manchmal ist weniger mehr.*/
    		printf
    		(
    			"Hauptmenü\n"
    			"*****************************************\n"
    			"*[1] Fuer Konvertierung Dezimal -> Oktal*\n"
    			"*[2] Fuer Konvertierung Oktal -> Dezimal*\n"
    			"*[3] Beenden*\n"
    			"*****************************************\n"
    			"Bitte Druecken Sie eine Zahl von 1 bis 3\n"
    			"Betätigen Sie Ihre Wahl mit RETURN: "
    		);  
    
    		/*Mit getchar den Input holen*/
    		input=getchar();
    		printf("\n");
    
    		/*Kleiner Trick: wir zwingen auf positive Werte - negative
    		**Werte werden damit sehr hohe positive, und dafür brauchen
    		**wir dann nur einen Check, ob die Option die gewuenschte ist.*/
    		if(input-'0'>3U)
    		{
    			/*Hat man uns eine leere Zeile gegeben?*/
    			if(input!='\n')
    				clear_input_stream('\n');
    			puts("Ungültige Eingabe!\n");
    			continue;
    		}
    
    		/*Korrekte Eingabe, man kann weitermachen.*/
    		printf("Auswahl: %c\n\n",input);
    		clear_input_stream('\n');
    
    		/*Und hier kommt dann halt dein Code hin.*/
    	}
    	while(input!='3');
    
    	/*Alles OK.*/
    	return 0;
    }
    

    Ja, das ist für einen Anfänger sehr kompliziert. Man erwartet nicht, dass du das sofort verstehst. Experimentiere ein bisschen mit dem Code herum; finde heraus, welche Zeile was macht.



  • dachschaden schrieb:

    Au Backe ... mit Windows als Entwicklungsplattform? Ich habe mich damals ein Jahr mit abgequält, bevor ich das mal unter Linux ausprobiert habe - beste Entscheidung in dem Jahr........

    hey!
    danke für diese gute erklärung! also bin jetzt bisschen weiter gekommen, aber mein problem besteht immernoch: wie schaff ich es dass nachdem ich einen durchlauf mit der konvertierung hatte, dass mein menü wieder erscheint? mit dieser do while schleife funktioniert es nicht ganz so gut, denn wenn ich ausversehen im menü einen buchstaben(oder kommazahl) eingebe statt eine ganze zahl, dann erscheint das menü 1000mal pro sekunde nacheinander und ich kann nichts mehr tun 😮

    ps. ja hab windows 😃 aber ich kann noch damit leben haha

    gruß teschk



  • Du probierst es immer noch mit scanf_s ?
    Weil meinen Code dies nicht tangiert. Dem kannst du beliebige Zeichen übergeben. scanf_s krepiert, wenn nicht das Zeichen, welches du erwartest, angegeben wurde. Keine Ahnung, warum das so ist, damals hatte man mir das als Feature für Compilerhersteller vorgestellt.

    Mein Code beruht darauf, dass ich erst mal das erste Zeichen vom Eingabestream lese, und dann prüfe, ob es sich um eine Zahl handelt:

    /*Zahl oder nicht Zahl?*/
    if(input-'0'>3U)
    

    Wenn es sich nicht um eine Zahl handelt ... nun, bei dir krepiert dann das Programm. Bei mir rufe ich nach jeder Eingabe clear_input_stream auf, die Funktion habe ich selbst geschrieben. Sie soll im Grunde sämtlichen Blödsinn, den der User noch angegeben hat, ignorieren. Und damit meine ich Blödsinn wie leere Zeilen, oder mehr Zeichen, als wir erwartet haben, oder keine Zahlen.

    Aaaber: Ich prüfe erst einmal, ob es sich um einen Zeilenumbruch handelt, den wir bekommen haben. Ein Zeilenumbruch sagt uns, dass die Eingabe abgeschlossen ist - und wenn das erste Zeichen ein Zeilenumbruch ist, ist das gleichbedeutend mit einer leeren Eingabe.

    Warum prüfe ich überhaupt auf diesen Zeilenumbruch?
    Wenn ich jetzt diese clear_input_stream -Funktion aufrufen würden, ohne vorher zu prüfen, ob die Eingabe leer - d.h. abgeschlossen - ist, würde das Programm noch mal eine Eingabe vom Nutzer abfragen. Weil keine Zeichen im Inputbuffer sind. Und diese Eingabe würde dann auch wieder verworfen werden. Bevor wir die Funktion also aufrufen, erst der Check.

    Aber die Funktion rufen wir auch dann auf, wenn die Eingabe erfolgreich war - heißt, wenn das erste gelesene Zeichen tatsächlich eine Zahl ist. Das machen wir, weil der Nutzer zum Beispiel auch 13467123349435 eingeben kann. Wir sind aber nur an der ersten Zahl interessiert, der Rest ist uns egal. Aaaber der Rest der Zeichen würde dann wieder von getchar zurückkommen - wir haben nur ein Zeichen geholt, aber die anderen warten nur darauf, dass wir sie abholen. Daran haben wir aber kein Interesse, wir wollen nur das erste Zeichen. Also verwerfen wir sie mit Aufrufen von getchar , und zwar so lange, bis wir wieder einen Zeilenumbruch (Ende der Eingabe) haben.

    Was würde passieren, wenn wir NICHT den Eingabebuffer leeren? Ein ähnliches Problem, wie du bei scanf_s hast, die Funktion würde beim nächsten Schleifendurchlauf nicht anhalten. scanf_s hat keine (mir bekannte) Möglichkeit, sich von einer falschen Eingabe zu erholen, fragt nichts mehr vom Nutzer ab und schickt nur noch Müll raus. Das führt dann zu dir dann beobachteten Endlosschleife.

    getchar würde nicht direkt in eine Endlosschleife gehen. Es würde nur nicht blocken, solange noch Zeichen im Eingabebuffer sind. Solange also 3467123349435 (erstes Zeichen haben wir schon) noch im Speicher steht, würde die Schleife für jede dieser Ziffern iterieren. Also noch 13 Mal. Mit clear_input_stream verwerfen wir den Blödsinn und leeren den Eingabebuffer für die nächste Benutzeraktion. Damit dann für den nächsten Schleifendurchlauf wieder Daten vom Nutzer kommen, und nicht Daten, die noch im Speicher stehen.



  • Löse dich mal davon, die Zeichen der Nutzereingabe irgnedwie umwandeln zu müssen (und als int weiterzuverarbeiten), du sollst sie direkt verarbeiten, d.h. als char abfragen:

    #include <stdio.h>
    
    int main()
    {
      while(1)
      {
        char s[100];
        int c;
        printf(" MENUE AUSWAHL\n");
        printf(" DRUECKEN SIE 1-3.\n");
        printf(" ****************************************\n");
        printf(" *[1]Fuer Konvertierung Dezimal -> Oktal*\n");
        printf(" *[2]Fuer Konvertierung Oktal -> Dezimal*\n");
        printf(" *[3] |----->ABBRUCH<-----| *\n");
        printf(" ****************************************\n");
        printf(" Bitte Druecken Sie eine Zahl von 1 bis 3\n bestaetigen Sie Ihre Wahl mit RETURN: ");
    
        switch((c=getchar(),fgets(s,100,stdin),c))
        {
        case '1':
          puts("========1=========");
          break;
        case '2':
          puts("========2=========");
          break;
        case '3':
          return 1;
        default :
          puts("fehlerhafte Eingabe");
        }
      }
      return 0;
    }
    


  • @Wutz: der Code hat das Problem, dass
    1. leere Zeilen nicht erkannt werden und der Nutzer zweimal eine Eingabe machen muss, von der die zweite vollkommen ignoriert wird.
    2. Wenn ich mehr als 100 Zeichen eingebe, die Schleife sich mehrmals wiederholt, um alles aus dem Eingabebuffer zu bekommen.



  • dachschaden schrieb:

    Du probierst es immer noch mit scanf_s ?
    Weil meinen Code dies nicht tangiert. Dem kannst du beliebige Zeichen übergeben. scanf_s krepiert, wenn nicht das Zeichen, welches du erwartest, angegeben wurde. Keine Ahnung, warum das so ist, damals hatte man mir das als Feature für Compilerhersteller vorgestellt........

    hey!
    ja du hattest recht ich hab immernoch das mit scanf benutzt...jetzt hab ich die getchar methode versucht und es klappt!!! mein menü erscheint nicht mehr in der endlosschleife 😃 😃

    ABER!: das problem ist:
    1. gibt es keine alternative zu

    clear_input_stream('\n');
    

    ? denn das ist komischerweise bei mir nicht definiert 😕

    ich danke euch herzlich für eure bemühungen!



  • Das ist ja auch eine Funktion, die ich selbst geschrieben habe ;). Siehste oben im Code (und auch noch mal hier):

    void clear_input_stream(char c)
    {
        while(getchar()!=c);
    }
    

    Die packst du VOR deine main -Funktion:

    void clear_input_stream(char c){/*Code*/}
    int main(void){/*Noch ganz viel mehr Code*/}
    

    Und dann sollte das hinhauen.

    Der Grund, warum ich der Funktion einen Parameter übergebe, ist relativ einfach: Es kann sein, dass man den Eingabebuffer auch nur bis zu einem bestimmten Zeichen leer haben will. Dann kann man dieses Zeichen halt so angeben.



  • dachschaden schrieb:

    Das ist ja auch eine Funktion, die ich selbst geschrieben habe ;). Siehste oben im Code (und auch noch mal hier):

    void clear_input_stream(char c)
    {
        while(getchar()!=c);
    }
    

    Die packst du VOR deine main -Funktion:

    void clear_input_stream(char c){/*Code*/}
    int main(void){/*Noch ganz viel mehr Code*/}
    

    Und dann sollte das hinhauen.

    Der Grund, warum ich der Funktion einen Parameter übergebe, ist relativ einfach: Es kann sein, dass man den Eingabebuffer auch nur bis zu einem bestimmten Zeichen leer haben will. Dann kann man dieses Zeichen halt so angeben.

    ahhhh achsooo haha ok ich verstehe 😃

    also mein problem ist jetzt wenn ich im menü 22 eingebe, glaubt das programm ich hab 2 eingeben statt zu sagen"ungültige eingabe".
    und wenn ich zb. im menü 1 eingebe und dann statt ne dezimalzahl einen buchstaben eingebe, erscheint mein menü zwei mal nacheinander 😕

    ohne deine hilfe wäre ich nie so weit gekommen!! ich weiß ich stell mich bissl doof an 🤡

    gruß teschk



  • Teschk schrieb:

    also mein problem ist jetzt wenn ich im menü 22 eingebe, glaubt das programm ich hab 2 eingeben statt zu sagen"ungültige eingabe".

    Ja, weil das Programm noch optimistisch genug ist, bei nur einer halbwegs korrekten Eingabe nicht direkt alles hinzuwerfen. Wenn schon das erste Zeichen korrekt ist, versucht das Programm, damit zu arbeiten. Frei nach dem Motto:

    Be conservative in what you send, be liberal in what you accept.

    Teschk schrieb:

    und wenn ich zb. im menü 1 eingebe und dann statt ne dezimalzahl einen buchstaben eingebe, erscheint mein menü zwei mal nacheinander 😕

    Jetzt hast du allerdings das Problem, dass das nicht so gut funktioniert, wenn du mehr als zwei Zeichen in der Konsole eingibst - wenn dein Programm also wirklich umwandeln soll. Deswegen musst du das Programm noch so abändern, dass es, wenn mehr als ein Zeichen/eine Ziffer eingegeben werden soll, dies auch korrekt abgearbeitet wird. Da kannst du dich nicht darauf verlassen, dass der Menücode so funktioniert.

    WIE man das am Besten macht, lasse ich dich aber selbst herausfinden. Mit getchar geht das, soviel kann ich dir sagen. 🙂 Und meine Musterlösung, die ich gerade geschrieben habe, löst sogar das Problem der "optimistischen Interpretation".

    Noch ein kleiner Tipp: wäre nicht verkehrt, wenn du für die Aufgabe lernst, wie man Zeichen in Ziffern für den Rechner umwandeln kann, und zwar zu einer gegebenen Basis.



  • Hey leute, vielen dank für eure hilfe ich bin dank euch viel weiter gekommen. 😃

    von mir aus könnt ihr dieses thema schließen 🙂

    jetzt weiß ich, wenn ich ein problem hab, werde ich mich zuerst an euch wenden haha 😛

    besonderen dank an dachschaden 👍

    gruß teschk


Anmelden zum Antworten