Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?



  • Hallo, ich habe ein Programm geschrieben, welches einzelne Funktionen aufruft, in denen dem User Fragen gestellt werden. Wenn dieser eine Frage jedoch falsch beantwortet, geht das Programm einfach zur nächsten Funktion. Wie bekomme ich es hin, dass es abbricht bzw. frägt ob man es erneut probieren möchte?

    Ich tippe auf die do while Schleife, finde dazu aber leider nichts..
    Wäre über jede Antwort dankbar.

    PS: Sorry dass ich es in C++ poste und nicht in C, aber das C Thread scheint mir ausgestorben zu sein. Es handelt sich ja um eine Frage, die man auch bei C++ hätte haben können.

    Viele Grüße!

    Hier meine Main Funktion:

     int main()
    {
    	do
    	{
    		erstefrage();
    		zweitefrage();
    		drittefrage();
    		Aussage1();
    
    
    
    		char jodern;
    
    		printf("\nMoechtest du nochmal von vorne anfangen? j/n\n");
    		scanf_s("%c", &jodern);
    		getchar();
    
    		if (jodern = 'j')
    		{
    			main();
    		}
    	} while ();
    
    }
    


  • In deinem Code sehe ich mehrere unschöne Probleme. Erstens solltest du vermeiden, die Main-Funktion rekursiv aufzurufen. Zweitens, auch wenn es für einen Anfänger schwer ist, versuche Ein- / Ausgabe von der Programm-Logik zu trennen.

    Ansonsten lass dir von der Funktion das Ergebnis zurück geben. - Das kannst du dann mit if-/else auswerten.



  • Danke für deine schnelle Antwort!

    Gibt es eine elegantere Art das Programm neu zu starten? Ich wollte nicht goto verwenden, ich habe gehört das sei auch keine gute Lösung. Die Ein & Ausgabe packe ich dann in eine extra Funktion, das ist es doch was du damit meinst, oder?

    Ok, ich muss also mit einem Rückgabewert arbeiten. Ist es da empfehlenswert das mit 1 (true) und 0 (false) zu machen oder bin ich auf dem Holzweg?



  • Klar, nimm den Main-Aufruf raus. - Denn nach deinem aktuellen Code schachtelst du nur Schleifen.

    Dein Ablauf ist momentan:
    - Fragen stellen
    - Abfrage ob erneut durchgeführt werden soll
    -> wenn ja Aufruf Main() => Fragen stellen...
    -> wenn nein => Fragen stellen...



  • @inflames2k sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

    Erstens solltest du vermeiden, die Main-Funktion rekursiv aufzurufen.

    Genau genommen ist es nicht erlaubt.



  • @themadjuli sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

    PS: Sorry dass ich es in C++ poste und nicht in C, aber das C Thread scheint mir ausgestorben zu sein. Es handelt sich ja um eine Frage, die man auch bei C++ hätte haben können.

    Das liegt auch daran, dass die Fragen hier gestelt werden 😉



  • @themadjuli sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

    Ich wollte nicht goto verwenden, ich habe gehört das sei auch keine gute Lösung.

    do {
    ...
    } while ( !abbruch );
    


  • Danke!
    Schon was gelernt; nicht die Main Funktion aufrufen, immer mit Schleifen arbeiten.

    So weit, so gut. Das Programm beenden funktioniert schon mal.

    Ich habe jetzt noch das Problem, dass selbst wenn eine Frage falsch beantwortet wird, das Programm erst einmal fortgesetzt wird, bis man alle Funktionen abgearbeitet hat.
    Das kann ich ja durch das Verwenden eines Rückgabewertes ändern, richtig?
    Wie gehe ich das am besten an?

    
    #include "pch.h"
    #include <iostream>
    
    //Funktion Prototypen
    void erstefrage();
    void zweitefrage();
    void drittefrage();
    void Aussage1();
    
    // Hauptfunktion
    
    
    int main()
    {
    	char jodern;
    	char n;
    	do
    	{
    		erstefrage();
    		zweitefrage();
    		drittefrage();
    		Aussage1();
    
    
    		getchar();
    		printf("\nMoechtest du nochmal von vorne anfangen? j/n\n");
    		scanf_s("%c", &jodern);
    
    	} while (jodern != 'n');
    
    	printf("\nDanke fuers mitmachen. Tschau!\n");
    }
    
    void erstefrage()
    {
    	char antwort;
    	int versuch = 0;
    	printf("\nHerzlich Willkommen in der Rakete. Sind Sie bereit fuer den Abschuss? j/n\n");
    	do
    	{
    		scanf_s("%c", &antwort);
    
    		if ((!antwort == 'j') || (!antwort == 'n'))
    		{
    			printf("\nSie sind wohl nicht bereit. Schade.\n");
    			break;
    		}
    
    		if (antwort == 'j')
    		{
    			printf("\nDann wollen wir mal!\n\n");
    			break;
    		}
    
    		if (antwort == 'n')
    		{
    			printf("Sind Sie sich sicher?\n");
    			versuch++;
    
    			if (versuch >= 5)
    			{
    				printf("\nChance verpasst.\n");
    				break;
    			}
    		} 
    
    	} while (versuch < 5);
    }
    
    void zweitefrage() 
    {
    	int alter;
    	printf("Ich moechte dir vorab noch ein paar Fragen stellen, um zu sehen ob du geeignet bist.\n\n");
    	printf("Wie alt bist du?\n");
    	scanf_s("%d", &alter);
    	if (alter < 18)
    	{
    		printf("Du bist zu jung um ins All zu fliegen, tut mir leid!\n");
    	}
    	else if (alter > 65)
    	{
    		printf("Du bist zu alt um ins All zu fliegen, tut mir leid!\n\n");
    	}
    	else if (alter >= 18 && alter <= 65) 
    	{
    		printf("\nSehr gut.\n");
    	}
    }
    
    void drittefrage()
    {
    	float groesse;
    	printf("\nWie gross bist du? Schreibe in cm! \n\n");
    	scanf_s("%f", &groesse);
    
    	if (groesse > 200)
    	{
    		printf("Du bist zu gross um ins All zu fliegen, tut mir leid!\n");
    	}
    
    	else if (groesse < 160)
    	{
    		printf("Du bist zu klein um ins All zu fliegen, tut mir leid!\n");
    	}
    	
    	else if (groesse >= 160 && groesse <= 200)
    	{
    		printf("\nSehr gut.\n");
    	}
    }
    
    void Aussage1() {
    	printf("\n\n- Du scheinst geeignet zu sein! - \n\n");
    	printf("Nur noch ein paar Formalitaeten und wir koennen dich ins All schiessen.\n");
    	printf("");
    }
    


  • @themadjuli sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

    Das kann ich ja durch das Verwenden eines Rückgabewertes ändern, richtig?

    Ja

    Wie gehe ich das am besten an?

    Du willst programmieren lernen. Denk drüber nach, probier was aus.



  • Hehe, richtig. Wollte es mir mal wieder zu einfach machen.
    Danke nochmal, ich probier mich mal.



  • Ich habe auch erst letztes Jahr so richtig mit programmieren angefangen. Schau am besten nach einem guten Buch. Glaub mir, dann kommen viele Fragen garnicht erst auf und du vermeidest es, dir bei manchen Problemen die falsche Lösungswege anzugewöhnen.



  • Lustigerweise könntest du hier Verschachtelung vermeiden und nur auf Short-circuit evaluation setzen.

    Deine Fragen-Funktionen geben alle entweder 1 (für weiter) oder 0 (zum Abbruch) zurück. Dann machst du einfach nur erstefrage() && zweitefrage() && drittefrage();.

    Ich find das knorkig.



  • Okay, das klingt interessant.
    Dann könnte ich nach meiner if Funktion in der main, einfach alle anderen Funktion durch && verbinden. So hätte ich einiges an Text gespart, denn wie man so schön sagt: in der Kürze liegt die Würze.

    Ich habe das aktuell noch wie folgt gelöst:

    
    #include "pch.h"
    #include <iostream>
    
    //Funktion Prototypen
    int erstefrage();
    int zweitefrage();
    int drittefrage();
    void Aussage1();
    
    // Hauptfunktion
    
    
    int main()
    {
    	char jodern;
    	char n;
    	do
    	{
    		if (erstefrage() == 0)
    		{
    			jodern = 'n';
    			break;
    		}
    		if (zweitefrage() == 0)
    		{
    			jodern = 'n';
    			break;
    		}
    		if (drittefrage() == 0)
    		{
    			jodern = 'n';
    			break;
    		}
    		Aussage1();
    
    
    		getchar();
    		printf("\nMoechtest du nochmal von vorne anfangen? j/n\n");
    		scanf_s("%c", &jodern);
    
    	} while (jodern != 'n');
    
    	printf("\nDanke fuers mitmachen. Tschau!\n");
    }
    
    int erstefrage()
    {
    	char antwort;
    	int versuch = 0;
    	printf("\nHerzlich Willkommen in der Rakete. Sind Sie bereit fuer den Abschuss? j/n\n");
    	do
    	{
    		scanf_s("%c", &antwort);
    
    		if ((!antwort == 'j') || (!antwort == 'n'))
    		{
    			printf("\nSie sind wohl nicht bereit. Schade.\n");
    			break;
    		}
    
    		if (antwort == 'j')
    		{
    			printf("\nDann wollen wir mal!\n\n");
    			break;
    		}
    
    		if (antwort == 'n')
    		{
    			printf("Sind Sie sich sicher?\n");
    			versuch++;
    
    			if (versuch >= 5)
    			{
    				printf("\nChance verpasst.\n");
    				return 0;
    			}
    		} 
    
    	} while (versuch < 5);
    }
    
    int zweitefrage() 
    {
    	int alter;
    	printf("Ich moechte dir vorab noch ein paar Fragen stellen, um zu sehen ob du geeignet bist.\n\n");
    	printf("Wie alt bist du?\n");
    	scanf_s("%d", &alter);
    	if (alter < 18)
    	{
    		printf("Du bist zu jung um ins All zu fliegen, tut mir leid!\n");
    		return 0;
    	}
    	else if (alter > 65)
    	{
    		printf("Du bist zu alt um ins All zu fliegen, tut mir leid!\n\n");
    		return 0;
    	}
    	else if (alter >= 18 && alter <= 65) 
    	{
    		printf("\nSehr gut.\n");
    		return 1;
    	}
    }
    
    int drittefrage()
    {
    	float groesse;
    	printf("\nWie gross bist du? Schreibe in cm! \n\n");
    	scanf_s("%f", &groesse);
    
    	if (groesse > 200)
    	{
    		printf("Du bist zu gross um ins All zu fliegen, tut mir leid!\n");
    		return 0;
    	}
    
    	else if (groesse < 160)
    	{
    		printf("Du bist zu klein um ins All zu fliegen, tut mir leid!\n");
    		return 0;
    	}
    	
    	else if (groesse >= 160 && groesse <= 200)
    	{
    		printf("\nSehr gut.\n");
    	}
    	return 1;
    }
    
    void Aussage1() {
    	char bereit;
    	char name[30];
    	printf("\n\n- Du scheinst geeignet zu sein! - \n\n");
    	printf("Nur noch ein paar Formalitaeten und wir koennen dich ins All schiessen.\n");
    	printf("\nBitte beachte dass dies ein Oneway Flug ist. \nDas heisst ab hier gibt es kein zurueck mehr.\n");
    	printf("Falls du bereit dafuer bist fahren wir fort.\nSag mir, bist du bereit mit der Rakete abzuheben? j/n\n");
    	getchar();
    	scanf_s("%c", &bereit);
    	printf("\nNa klar bist du bereit. \nSonst haettest du dich nicht fuer unser Auswahlprogramm entschieden.\n");
    	printf("Nun brauche ich aber erst einmal deinen Namen: ");
    	getchar();
    	scanf_s("%s", &name);
    	printf("Hallo %c.\n\n", name);
    }
    


  • Bestehen überhaupt noch Fragen? Das ist mir nicht ganz klar, trotzdem mal ein paar Anmerkungen meinerseits (in der Hoffnung das evtl. ein paar davon nützlich sind für Dich):

    // erstefrage()
    if ((!antwort == 'j') || (!antwort == 'n'))
    

    Das macht zu 99% nicht was Du eigentlich willst. Schau mal hier. Das not (!) bezieht sich nur auf antwort und das Ergebnis daraus wird mit 'j' verglichen. Eher so:

    if (antwort == 'j')
       // ...
    else if (antwort == 'n')
       // ...
    else // antwort != 'j' && antwort != 'n' (das ist Implizit der Fall und wird beim Programmieren i.d.R. nicht nochmal extra hingeschrieben)
       // ...
    

    Ich würde Dir empfehlen, erstmal nur mit einer einzigen Frage-Funktion zu arbeiten, bis alles klappt wie Du willst, und dann die Anderen hinzuzufügen. Im Forum am Besten das Programm so weit verkleinern bis nur noch der Fehler, den Du gerade lösen willst, übrig bleibt.

    Persönlich finde ich do-while Schleifen (meistens) ungeschickt, weil die Bedingung am Ende der Schleife steht und das schadet IMHO der Lesbarkeit!

    Es müsste einen header <stdbool.h> geben, womit Du auch Zugriff auf 'bool', 'true' und 'false' hast. Dann braucht man nicht mehr mit int arbeiten, wo man eigentlich einen bool will (wobei ich weiß nicht genau wie das in C ist). Siehe bool in C.

    Bei zweitefrage() und drittefrage() ist die Bedingung im letzten else-if ebenfalls überflüssig: Da Du schon weißt, dass groesse <= 200 und groesse >= 160, wenn du einfach nur einen else-Block am Ende nimmst, also so:

    if (groesse > 200)
        // zu gross
    else if (groesse < 160)
        // zu klein
    else
       // genau richtig: 160 <= groesse <= 200
    

    Klar könnte man noch extra hinschreiben groesse >= 160 && groesse <= 200, aber das ist nach m. E. eher verwirrend und vielleicht bockt man sich noch ungewollte Tippfehler ein o. Ä.

    Da die Funktion auch etwas ganz bestimmtes macht (die Größe einlesen und prüfen) würde ich eher einen Namen wählen, der mehr über die Funktion sagt, z.B. "pruefe_groesse" o. Ä. ... Wenn wir schon dabei sind, am Besten dann noch aufteilen in eine Funktion, welche die Größe einließt und eine separate Funktion, welche prüft (wurde ja schon angesprochen). Bsp:

    bool groesse_ok(float groesse) {
        return 160.f <= groesse && groesse <= 200.f;
    }
    
    // weiß nicht wie man die Schnittstelle hier in C optimalerweise gestalten würde
    float groesse_einlesen() { 
            float groesse;
    	printf("\nWie gross bist du? Schreibe in cm! \n\n");
    	scanf_s("%f", &groesse);
            return groesse;
    }
    

    Das mag im ersten Moment unscheinbar sein, aber: Durch diese Unterscheidung zwischen Eingabe und Verarbeitung (und Ausgabe) werden Programme besser strukturiert und einfacher erweiterbar. Das selbe Prinzip gilt auch z.B. für zweitefrage().

    In der main() willst Du wahrsch. etwas in dieser Richtung haben:

    int main()
    {
        while (!viertefrage()) {
            if (!fuenftefrage())
                return 0;
        }
        Aussage1();
        // Danke fürs mitmachen
    }
    

    viertefrage kombiniert nur die erste, zweite und dritte, so wie es schon erwähnt wurde (mit &&). Werden alle Fragen zufriedenstellend beantwortet, dann bricht die while-Schleife ab und es kommt Aussage1() und die Abschlussnachricht.

    fuenftefrage frägt den Nutzer, ob er nochmals versuchen will oder nicht, falls eine der Fragen nicht zufriedenstellend beantwortet wurde. Wenn er mit Ja antwortet, wird er nochmals gefragt, sonst beendet das Program.

    Aussagekräftige Namen für Variablen und Funktionen sind sehr wichtig, damit größere Programme verständlich bleiben!

    Ich habe das Gefühl (vielleicht liege ich auch falsch), dass Du break mit continue verwechselst. break bricht die Schleife komplett ab und das was danach kommt wird weiter ausgeführt (im Fall von erstefrage() kommt nichts, und es fehlt ein Rückgabewert!). continue springt wieder zum Anfang der Schleife, wo die Bedingung geprüft wird. Zur Sicherheit: continue vs. break.

    LG



  • @themadjuli sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

      if (erstefrage() == 0)
      {
      	jodern = 'n';
      	break;
      }
      if (zweitefrage() == 0)
      {
      	jodern = 'n';
      	break;
      }
      if (drittefrage() == 0)
      {
      	jodern = 'n';
      	break;
      }
    

    Was soll das setzten von jodern bewirken - es wird später doch sowieso überschrieben. break in der letzten Zeile vor einem Blockende ist auch ziemlich sinnfrei.

    Und du benutzt scanf_s() falsch:

    scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s:

    int scanf_s(const char *restrict format, ...); (4)
    [...]
    4-6) Same as (1-3), except that %c, %s, and %[ conversion specifiers each expect two arguments (the usual pointer and a value of type rsize_t indicating the size of the receiving array, which may be 1 when reading with a %c into a single char)

    Wozu überhaupt printf() und scanf() in einem C++-Programm? Der Header <cstdio> dafür fehlt auch und die Funktionen liegen im Namespace std.



  • @themadjuli sagte in Anfänger Frage: Programm das Fragen abarbeitet wie stoppen?:

    Sorry dass ich es in C++ poste und nicht in C, aber das C Thread scheint mir ausgestorben zu sein. Es handelt sich ja um eine Frage, die man auch bei C++ hätte haben können.

    Poste gefälligst im richtigen Forum, wenn Du schon weißt, daß Du hier falsch bist 👎🏻

    Dann eben anders rum: Was soll der Header <iostream> in einem C-Programm? Und es heißt int main(void).



  • Vielen Dank HarteWare für deine ausführliche Antwort! Ich konnte einiges lernen und bin gerade am umsetzen. Genau solche Antworten braucht man am Anfang 🙂 Super erklärt, vielen Dank!