Falsche Eingaben anfangen



  • Hallo!

    Wir müssen ein C-Progamm schreiben, welches positive int-Werte aus dem Dezimalsystem in versch. Zahlensysteme umrechnet (Basis 2-16, umzurechende Zahl unsigned int). Bei der Frage nach dem Wert, der umgerechnet werden soll, und der Basis sollen wir falsche Eingaben abfangen. Also wenn man Buchstaben oder negative Zahlen bzw.zu große Zahlen eingibt, dann soll ein Hinweis erfolgen und neu gefragt werden. Das habe ich zur Eingabe geschrieben:

    printf ("       Welche Zahl soll umgerechnet werden? " );
    scanf ("%i" , &x);
    
    printf("        Welche Basis soll die Umgerechnete Zahl haben? ");
    scanf("%i" , &b);
    

    Kann mir vielleicht jemand helfen, wie ich dasmit den falschen Eingaben mache (der Rest des Programms steht)? Vermutlich muss ich eine Schleife laufen lassen, doch ich weiß nicht wie...

    Besten Dank schon mal!

    Viele Grüße



  • scanf returnt die anzahl erfolgreich gescannter variablen. damit erkennst du, ob was gescheites eingegeben wurde.

    du moechtest wohl eine do-while schleife.



  • Hab die Lösung 🙂

    printf (" Welche Zahl soll umgerechnet werden? " );
    		do
    		{
    			t=scanf ("%d" , &x);
    			fflush(stdin);
    			if (t !=1)
    			printf ("\nFehler bitte Neueingabe: ");
    		}
    		while (t != 1);
    


  • wieso sieht man in so kleinen Zeitabstände so sinnlose Sachen wie fflush(stdin) 😕 ???





  • supertux schrieb:

    wieso sieht man in so kleinen Zeitabstände so sinnlose Sachen wie fflush(stdin) 😕 ???

    Das liegt daran, dass es einfach zu oft in Tutorials, Skripten und Büchern vorkommt. Da die Autoren meist selbst nicht wissen (oder wissentlich ignorieren), dass fflush(stdin) nicht portabel ist, wird sich da wohl auch nicht so schnell ändern. Leider...



  • Siddhartha schrieb:

    Wir müssen ein C-Progamm schreiben, welches positive int-Werte aus dem Dezimalsystem in versch. Zahlensysteme umrechnet[...]

    da hast du noch was vergessen 😉
    mach deine schleife so:

    while(t != 1 && x < 0)
    


  • Jay schrieb:

    da hast du noch was vergessen 😉
    mach deine schleife so:

    while(t != 1 && x < 0)
    

    Vielen Dank! Doch leider klappt es nicht (ich glaube, es liegt daran, dass die negativen Werte intern anders dargestellt werden).

    c.rackwitz schrieb:

    http://c-plusplus.net/forum/viewtopic-var-t-is-39349.html
    C/C++ Forum :: fflush(stdin); ??

    Die Variante die dort vorgeschlagen wurde klappt auch nicht.

    Hier ist mal das ganze Programm, vielleicht wollt Ihr es Euch mal ansehen. Wenn nicht, ist es nicht sooo schlimm. Ich bin noch Anfänger, vielleicht gibt es elegantere Lösungen als meine if-Konstruktion in der Schleife für die Basis.

    #include <stdio.h>
    
    int main (void)										/*zahlensysteme*/
    {
    	unsigned int i  , x , b, z, n, hb, hx, f, t;
    
    	do
    	{
    		n=0;
    		printf ("\n\n  *** Umrechnungsprogramm in ein Zahlensystem beliebiger Basis von 2-16 ***\n\n");
    		printf ("       Welche Zahl soll umgerechnet werden? " );
    		do
    		{
    			t=scanf ("%d" , &x);
    			fflush(stdin);
    			if (t !=1)
    			printf ("\n       Fehler bitte Neueingabe: ");
    		}
    		while (t != 1);
    
    		printf("\n\n\n       Welche Basis soll die Umgerechnete Zahl haben? ");
    		do
    		{
    			t=scanf ("%d" , &b);
    			fflush(stdin);
    			if (t !=1) 
    			printf ("\n       Fehler bitte Neueingabe: "); 
    			else 
    			{
    				if (b>16)
    				{
    					printf ("\n       Fehler bitte Neueingabe: ");
    					t=0;
    				}
    				else
    				{
    					if (b<2)
    					{
    						printf ("\n       Fehler bitte Neueingabe: ");
    						t=0;
    					}
    				}
    			}
    		}
    		while (t != 1);
    
    		printf("\n\n\n\n                     Ergebnis: ");
    
    		hx=x;
    
    		for (n=1;hx>=b;0)			/*  Zur Ermittlung des höchsten Exponentes */
    		{
    			hx=hx/b;       	    		/*	hx ist die Hilfszahl. Für jedes Mal, dass hx durch die Basis b teilbar ist, erhöht sich der max. exponent um 1, */
    									/*	ist sie gar nicht teilbar, bleibt er 0.	Der Rest wird weggelassen.											*/
    			/*printf ("\n hx=%i \n n=%i\n" , hx, n);  /* für Tests beim Programmieren*/
    
    			n++;
    		}
    
    		do
    		{
    			hb=1;				/*	hb ist die Hilfsbasis, ist n=0, bleibt hb=1, ist n=zahl, wird hb=1*b^zahl */
    			for (i=1;i<n;i++)
    			hb = b * hb;
    			z = x / hb;			/* z ist die Ziffer =  x / hb */
    			printf ("%x",z);		/* Ziffern von 1-f sind möglich, werden jedoch nur bei Bedarf genutzt (also bei Zahlensystemen <= dezimal nicht) */
    			x= x % hb;
    			n=n-1;				/* der Exponent wird pro Schleifendurchlauf um 1 verringert */
    
    			/*printf ("\nx:%i \n z=%i \n hb=%i \n n=%i\n" , x,z,hb,n);   /* für Tests beim Programmieren*/
    		}
    		while (n>0);
    
    		printf ("\n\n\n");
    
    	printf("               Wiederholen(ja=1, nein=2)? ");
    	scanf("%i",&f);
    	printf ("\n\n");
    	}
    	while (f==1);
    
    return 0;
    }
    


  • sorry, statt dem && muss man natürlich ein || nehmen. somit könnte die eingabe der basis beispielsweise so aussehen:

    int c,b;
    do
    {
        printf("Bitte gültige Basis eingeben: ");
        scanf ("%d", &b);
        while ((c = getchar()) != EOF && c != '\n'); //eingabepuffer leeren
    } while (b < 2 || b > 16);
    

    ist vielleicht auch sinnvoll deine "umrechnung" in eine funktion auszulagern...



  • unsigned read_number(chsr const *prompt) {
      unsigned number;
      int scan_result;
      char buffer[100];
    
      do {
        printf("%s", prompt);
        fflush(stdout);
        fgets(buffer, 100, stdin);
        sscanf(buffer, "%u", &number);
      } while(scan_result != 1)
    
      return number;
    }
    
    // ...
    
    unsigned num = read_number("Bitte Zahl eingeben: ");
    


  • Eh, mein Fehler. Das muss natürlich

    scan_result = sscanf(buffer, "%u", &number);
    

    heißen.



  • Jay schrieb:

    sorry, statt dem && muss man natürlich ein || nehmen. somit könnte die eingabe der basis beispielsweise so aussehen:

    int c,b;
    do
    {
        printf("Bitte gültige Basis eingeben: ");
        scanf ("%d", &b);
        while ((c = getchar()) != EOF && c != '\n'); //eingabepuffer leeren
    } while (b < 2 || b > 16);
    

    ist vielleicht auch sinnvoll deine "umrechnung" in eine funktion auszulagern...

    Vielen Dank, der Hinweis mit dem || hat mir sehr geholfen. Das fflush(stdin); benutze ich aber doch, weil es ja klappt und es auch so im Skript steht. Wenn ich bei der umzurechnenden Zahl nämlich

    while ((c = getchar()) != EOF && c != '\n'); //eingabepuffer leeren
    

    benutze, dann weist er keine Buchtaben ab (vermutlich stellt er sie intern als Zahl dar).

    Also so ist nun das Programm:

    #include <stdio.h>
    
    int main (void)										/*zahlensysteme*/
    {
    	int i  , x , b, z, n, hb, hx, f, t;
    
    	do
    	{
    		n=0;
    		printf ("\n\n\n  *********************************************************");
    		printf ("\n  ***   Umrechnungsprogramm fuer positive Zahlen        ***");
    		printf ("\n  ***   in ein Zahlensystem beliebiger Basis von 2-16   ***");
    		printf ("\n  *********************************************************");
    		printf ("\n\n       Welche Zahl soll umgerechnet werden?\n " );
    
    		do
    		{
    			printf ("\n       Bitte positive Zahl eingeben: ");
    			t=scanf ("%d" , &x);
    			fflush(stdin);
    		}
    		while (t != 1 || x<0);
    
    			printf("\n\n       Welche Basis soll die Umgerechnete Zahl haben?\n");
    
    		do 
    		{ 
     			printf("\n       Bitte gueltige Basis eingeben (2-16): "); 
     			t=scanf ("%d" , &b);
    			fflush(stdin);
    		} while (t != 1 || b < 2 || b > 16);
    
    		printf("\n\n\n                     Ergebnis: ");
    
    		hx=x;
    
    		for (n=1;hx>=b;0)	/*  Zur Ermittlung des höchsten Exponentes */
    		{
    			hx=hx/b;		/*	hx ist die Hilfszahl. Für jedes Mal, dass hx durch die Basis b teilbar ist, erhöht sich der max. exponent um 1, */
    							/*	ist sie gar nicht teilbar, bleibt er 0.	Der Rest wird weggelassen.	*/
    			/*printf ("\n hx=%i \n n=%i\n" , hx, n);  /* für Tests beim Programmieren*/
    
    			n++;
    		}
    
    		do
    		{
    			hb=1;				/*	hb ist die Hilfsbasis, ist n=0, bleibt hb=1, ist n=zahl, wird hb=1*b^zahl */
    			for (i=1;i<n;i++)
    			hb = b * hb;
    			z = x / hb;			/* z ist die Ziffer =  x / hb */
    			printf ("%x",z);		/* Ziffern von 1-f sind möglich, werden jedoch nur bei Bedarf genutzt (also bei Zahlensystemen <= dezimal nicht) */
    			x= x % hb;
    			n=n-1;				/* der Exponent wird pro Schleifendurchlauf um 1 verringert */
    
    			/*printf ("\nx:%i \n z=%i \n hb=%i \n n=%i\n" , x,z,hb,n);   /* für Tests beim Programmieren*/
    		}
    		while (n>0);
    
    		printf ("\n\n  *********************************************************");
    
    		printf ("\n\n");
    
    	printf("               Wiederholen(ja=1, nein=2)? ");
    	scanf("%i",&f);
    	printf ("\n\n");
    	}
    	while (f==1);
    
    return 0;
    }
    


  • benutz doch aussagekräftige integer namen, das ist doch schlimm, besonders die selbsterklärenden kommentare



  • gewoehn dir das fflush(stdin) ab.
    und nenne den, der dir das so gezeigt hat, oeffentlich einen dummkopf.



  • c.rackwitz schrieb:

    und nenne den, der dir das so gezeigt hat, oeffentlich einen dummkopf.

    Super Tip, meine Bewunderung. 👎



  • applaus schrieb:

    c.rackwitz schrieb:

    und nenne den, der dir das so gezeigt hat, oeffentlich einen dummkopf.

    Super Tip, meine Bewunderung. 👎

    vielleicht kann man dann das fflush(stdin) stoppen. Hier sieht man jeden Tag fflush(stdin) oder void main, oder was weiß ich. Und die Ausrede ist immer dieselbe: "Im Buch stand so", "mein Lehrer schrieb es so", "Unser Proff. meinte...". Diese sind Dummkopfe, wenn sie ein undefiniertes Verhalten beibringen.



  • supertux schrieb:

    ... wenn sie ein undefiniertes Verhalten beibringen.

    Undefiniert ? Wieso ?



  • Weil es im Standard so festgelegt ist - fflush() leert den Ausgabepuffer eines FILE's, was er bei reinen Eingabedateien machen soll, ist nicht festgelegt (stdin hat keinen Ausgabepuffer, den du leeren könntest ;)).



  • CStoll schrieb:

    fflush() leert den Ausgabepuffer eines FILE's...

    flush bedeutet nicht einfach nur leeren.
    'flush' bedeutet, dass alle gepufferten daten sofort an die 'datensenke' geschickt werden sollen.
    im fall von stdin würde es bewirken, dass alle funktionen deines programms, die daten von stdin erhalten sollen, diese sofort kriegen. sowas würde den ganzen programmablauf durcheinanderbringen, deshalb geht es nicht.
    🙂



  • vista schrieb:

    CStoll schrieb:

    fflush() leert den Ausgabepuffer eines FILE's...

    flush bedeutet nicht einfach nur leeren.

    OK, da habe ich es wohl zu stark vereinfacht. fflush() überträgt die geschriebenen Daten aus dem Pufferbereich des FILE's zu dessen externer Repräsentation (Festplatte/Monitor/Drucker/...).

    Daß die Anweisung "fflush(stdin);" compiliert wird, liegt daran, daß C keine Unterscheidung zwischen Eingabe- und Ausgabe-Dateien trifft - unter C++ gibt es die Basisklassen istream (Eingabe), ostream (Ausgabe) und iostream (Ein- und Ausgabe) - und nur die letzten beiden verstehen ein flush(). Daß es von führenden "Experten" immer wieder aufgeführt wird, liegt vermutlich an der Verbreitung von MS - deren Compiler haben den Standard soweit erweitert, daß du mit fflush(stdin) den Rest des Tastaturpuffers entsorgen kannst.


Anmelden zum Antworten