Eingabe nach If-Anweisung nicht möglich



  • Guten Abend,

    ich bin absoluter C-Neuling, habe auch kein Informatik studiert, möchte aber die Programmiersprache C lernen.
    Ich arbeite auf einem Linux Laptop und habe mir Code::Blocks als IDE installiert. Nun arbeite ich Aufgaben aus einem Buch durch, ab und an versuche ich aber auch eigene Ideen zu programmieren und stecke bei einem, für Profis wohl sehr einfachen, Code fest.

    Soll-Funktion des Programms:
    Man entscheidet sich zwischen zwei Optionen, daraufhin soll ein Text eingegeben werden.
    Dazu habe ich folgenden Code geschrieben:

    void main(){
    int option;
    char satz[100];
    printf("(1) Option A        (2) Option B \n > ");
    scanf("%i", &option);
    if(option ==1){
        printf("\nBitte Kontrolltext eingeben:\n > ");
        fgets(satz, 100, stdin);
        /*   while(satz[i]){
                printf("%c",satz[i++]);
     }*/
     }
    printf("\nZeichenanzahl: %li\n", strlen(satz));
    

    Sobald ich nun die 1 im Terminal eintippe (für Option A) läuft das Programm durch, ich kann aber keinen Text eingeben und es zeigt mir an der - eigentlich nicht eingegebene - Text hätte 1 Zeichen. Lösche ich die If-Anweisung heraus, kann ich den Text zwar eingeben aber vorab nicht zwischen den Optionen wählen.

    Was mache ich hier falsch?

    Danke!


  • Mod

    \n stehe für ein Zeilenumbruchszeichen. Denn Zeilenumbrüche sind für den Computer auch nur ein spezielles Zeichen. Dann sieht dein Programm diese Zeichen eines nach dem anderen von der Eingabe kommen: "1\nDein Satz". Das %i bei scanf interessiert sich nur für Zahlen, dem ist der Zeilenumbruch egal, der wird gar nicht angefasst, weil keine Zahl. Es liest nur die 1, weil Zahl. Nachdem das scanf also fertig ist, kommt beim fgets also noch "\nDein Satz" an. fgets liest bis zum ersten \n (inklusive). Und das steht nun ganz vorne. Daher wird also nur genau dieses eine Zeilenumbruchszeichen vom fgets gelesen, und das ist, was bei dir passiert. Tatsächlich hast du sogar niemals Gelegenheit, deinen Satz überhaupt einzugeben, denn das fgets ist ja sofort fertig und hat keinen Grund, zu halten.

    Abhilfe: Da gibt es mehrere Möglichkeiten. Du könntest vor dem fgets ein scanf(" "); machen, das würde sämtlichen Whitespace verwerfen, der vor dem fgets kommt. Oder du kannst ganz auf fgets verzichten und stattdessen scanf nehmen mit einem cleveren Formatstring, der erst allen Whitespace verwirft und dann bis zu 100 nicht-Zeilenumbrüche liest (scanf ist ganz schön mächtig und kann das!).



  • ich habe das bei mir so gelöst, dass ich einfach keine zahlen direkt mit scanf einlese, sondern nur den eingabestring:

    char buffer[1024];
    
    scanf("%1023s", buffer);
    sscanf(buffer, "%i", &option);
    

    alternativ könntest du auch einfach den rückgabewert von fgets (oder scanf) auswerten.



  • @Peter-Viehweger sagte in Eingabe nach If-Anweisung nicht möglich:

    scanf("%1023s", buffer);
    sscanf(buffer, "%i", &option);

    Auch das läßt das '\n' im Eingabestrom stehen.
    Und für Texte mit Whitespace funktioniert das auch nicht.



  • so gehts aber, oder nicht?

    edit: irgendwas stimmt da nicht...



  • Hallo und danke soweit!

    Ich habe nun fgets mit scanf und die If-Anweisung mit einer switch-case Anweisung ersetzt.
    Wenn ich nun wieder die 1 eintippe bekomme ich wieder den Text "Bitte Kontrolltext eingeben" im Terminal angezeigt, dann passiert für einen Bruchteil nichts, dann aber kommt folgende Fehlermeldung: "Speicherzugriffsfehler (Speicherabzug geschrieben)".

    Ich verstehe hier meinen Logik- bzw. Programmierfehler nicht.

    Könnte hier ein Profi ein Beispiel geben wie der Code richtigerweise lauten müsste? Danke!



  • @Joe_der_neue dann zeig doch mal deinen neuen, fehlerhaften Code mit switch-case.

    Beim Kompilieren kannst & solltest du außerdem Warnungen aktivieren (bei gcc mit mindestens -Wall -Wextra). Und außerdem könntest du deinen Code auch mal durch clang-tidy laufen lassen. Gut möglich, dass die dein Fehler da schon angezeigt wird.



  • so?

    #define _CRT_SECURE_NO_WARNINGS
    
    #include <stdio.h>
    #include <string.h>
    
    void main()
    {
    	int option;
    	char satz[100];
    
    	printf("(1) Option A        (2) Option B \n > ");
    	fgets(satz, sizeof(satz) / sizeof(*satz) - 1, stdin);
    	sscanf(satz, "%i", &option);
    
    	if(option == 1)
    	{
    		printf("\nBitte Kontrolltext eingeben:\n > ");
       	        fgets(satz, sizeof(satz) / sizeof(*satz) - 1, stdin);
    
    		//while(satz[i]){
    				//printf("%c",satz[i++]);
    
    	}
    
    	printf("\nZeichenanzahl: %lli\n", strlen(satz)); // %lli!
    }
    
    (1) Option A        (2) Option B
     > 1
    
    Bitte Kontrolltext eingeben:
     > hallo dies ist ein test
    
    Zeichenanzahl: 24
    


  • @Peter-Viehweger sagte in Eingabe nach If-Anweisung nicht möglich:

    fgets(satz, sizeof(satz) / sizeof(*satz) - 1, stdin);

    Warum das -1 ?



  • Hi und danke soweit.
    Es funktioniert mit Peters Code so wie ich es will, ich habe aber noch Nachfragen zwecks Verständnis:

    	printf("(1) Option A        (2) Option B \n > ");
    	fgets(satz, sizeof(satz) / sizeof(*satz) - 1, stdin);
    	sscanf(satz, "%i", &option);
    

    Mein Verständnis ist, dass der Code Zeile für Zeile abgearbeitet wird. Warum wird fgets hier geschrieben aber erst nach sscanf ausgeführt?

    printf("\nZeichenanzahl: %lli\n", strlen(satz)); // %lli!
    

    Hier erscheint folgende Meldung:
    "format ‘%lli’ expects argument of type ‘long long int’, but argument 2 has type ‘size_t’ {aka ‘long unsigned int’} [-Wformat=]"

    Ändere ich das auf "li" funktioniert alles bestens.



  • @wob Mir werden die Warnungen im Terminal angezeigt sobald ich mit gcc compiliere.

    Code::Blocks sollte doch auch einen eigenen Debuger haben?! Gibt es da eine Möglichkeit den Code Zeile für Zeile zu compilieren und bei Fehlern die entsprechende Meldung zu erhalten? Ich kenne das so ähnlich aus VBA.


  • Mod

    @Joe_der_neue sagte in Eingabe nach If-Anweisung nicht möglich:

    Mein Verständnis ist, dass der Code Zeile für Zeile abgearbeitet wird. Warum wird fgets hier geschrieben aber erst nach sscanf ausgeführt?

    Wie kommst du darauf? Das passiert schon alles schön nacheinander. Beachte, dass Peter-Viehweger hier einen anderen Weg geht, als andere Antworten erklärt haben. Erst liest er eine ganze Zeile in einen String, und dann holt er aus diesem String eine Zahl heraus. sscanf ist was anderes als scanf.

    printf("\nZeichenanzahl: %lli\n", strlen(satz)); // %lli!
    

    Hier erscheint folgende Meldung:
    "format ‘%lli’ expects argument of type ‘long long int’, but argument 2 has type ‘size_t’ {aka ‘long unsigned int’} [-Wformat=]"

    Ändere ich das auf "li" funktioniert alles bestens.

    Weil beides falsch ist 🙂 Oder zumindest nicht richtig. Was genau ein size_t ist, hängt vom System ab, daher bekommt man solche Probleme, wenn man sich auf %li oder %lli festlegt. Zumal das auf jeden Fall ein unsigned Typ (%u) ist, daher ist alles mit %i sowieso die falschge Richtung. Der portable Formatspezifizierer für einen size_t ist %zu.

    (Ganz uralte Compiler können evtl. kein %zu. In dem Fall nimmt man einen Typ, der garantiert groß genug ist, und castet dahin. Etwa printf("%llu", (unsigned long long) value);)



  • @DirkB sagte in Eingabe nach If-Anweisung nicht möglich:

    Warum das -1 ?

    weil ich die dokumentation nicht gelesen / verstanden habe.

    @SeppJ sagte in Eingabe nach If-Anweisung nicht möglich:

    Der portable Formatspezifizierer für einen size_t ist %zu.

    ja ich erinnere mich.



  • Alles klar. Ich denke mein C- Büchlein ist da etwas zu alt oder ggf. kommen diese Funktionen und Platzhalter in den späteren Kapiteln...



  • wahrscheinlich nicht, weil es irgendwie keine neuen bücher für c gibt. um das lesen der dokumentation dieser ganzen funktionen im internet, oder wo auch immer, wirst du nicht drum herumkommen. das buch ist nur quasi "starthilfe".


  • Mod

    This post is deleted!


  • @Joe_der_neue sagte in Eingabe nach If-Anweisung nicht möglich:

    Alles klar. Ich denke mein C- Büchlein ist da etwas zu alt oder ggf. kommen diese Funktionen und Platzhalter in den späteren Kapiteln...

    HAst du die den schon mal die "Linkliste für Neuling" hier im Forum angesehen?
    https://www.c-plusplus.net/forum/topic/300567/linkliste-für-neulinge

    Auf Wikipedia sind die Änderungen von C zusammengefasst: https://de.wikipedia.org/wiki/Varianten_der_Programmiersprache_C

    Und in den Referenzen wird sogar gezeigt, wann die Änderungen eingeführt wurden. Beispiel für printf, die gelben Zellen gab es mit C99: https://cplusplus.com/reference/cstdio/printf/
    (Es sollte einem dabei klar sein, wie der Formatspecifier aufgebaut ist)


Log in to reply