Benötige Erklärung für char me [20]; --- Anfängerprobleme ---



  • Dein Buch ist Schrott.
    TocToc auch keine Ahnung, weil er wie üblich Unsinn erzählt.

    Die einzig korrekte Lösung wäre

    char me[20]; /* Definition von Speicherplatz für einen max. 19 Zeichen langen C-String */
       printf("Wie heissen sie?");
       scanf("%19[^\n]", me); /* liest max. 19 Zeichen, '\0' wird immer angehängt */
       while( getchar()!='\n' ); /* leert alle nicht gelesenen Zeichen inkl. des bei scanf immer terminierenden vorhandenen '\n' aus stdin, damit folgende stdin-Operationen keinen Schaden nehmen */
    

    Beachte die while-Schleife danach, die wird von 99% aller Tutorials/Bücher und 100% aller Anfänger hier im Forum ignoriert.



  • Zuviele Informationen aufeinmal. 😕 Ich kenne diese ganzen Befehle nicht einmal.



  • Welches Buch würdest du für einen Anfänger denn so empfehlen?



  • für Anfänger:

    Prata: C Primer Plus

    für Fortgeschrittene:

    Koenig: C Traps and Pitfalls
    Kernighan/Ritchie: The C Programming Language
    Kernighan/Ritchie: Programmieren in C (dt. Übersetzung)



  • Sorry, bin erst 16. So gut sind meine Englischkenntnisse noch nicht. 😃

    Würde man es dennoch eventuell schaffen zu verstehen? Wenn man ja die ganzen Wörter nachschlägt etc. Oder sind sehr gute Englischkenntnisse für das Buch: "Prata: C Primer Plus" erforderlich?



  • Bleib erstmal bei dem Buch.

    Hauptsache Dir macht das ganze Spaß.

    Du hast auf jeden Fall schon was sehr wichtiges entdeckt, nur dass ein Programm läuft heißt nicht, dass es richtig ist.
    In diesem Fall:
    Wenn Du in einen Puffer mehr reinschreibst als er groß is läuft er über (engl. Buffer overflow). Das ist ein ernster Fehler.

    Das mit dem Wertebereich -128...127 ist übrigens was ganz anderes...lies erstmal weiter.

    Ganz wichtig: aktivier Warnungen Deines Compilers - z.B. gcc -Wall -pedantic ... beim gcc.

    Zum Abschluß noch das Einführungsbeispiel von K&R zum thema scanf() . Ist auch nicht gegen Pufferüberläufe gesichert. 😉

    int day, year;
    char monthname[20];
    scanf("%d %s %d", &day, monthname, &year);
    


  • TocToc auch keine Ahnung, weil er wie üblich Unsinn erzählt.

    <333

    @Bladestorm: Wenn du fgets() kennst, benutze es denn es ist, wie ich vor ein paar tagen/Wochen erfahren hab um einiges besser. 🙂



  • Wenn du fgets empfiehlst, hast du scanf nicht verstanden.

    Beide haben Vor- und Nachteile und auch Tücken.



  • Wutz schrieb:

    Dein Buch ist Schrott.
    TocToc auch keine Ahnung, weil er wie üblich Unsinn erzählt.

    Die einzig korrekte Lösung wäre

    char me[20]; /* Definition von Speicherplatz für einen max. 19 Zeichen langen C-String */
       printf("Wie heissen sie?");
       scanf("%19[^\n]", me); /* liest max. 19 Zeichen, '\0' wird immer angehängt */
       while( getchar()!='\n' ); /* leert alle nicht gelesenen Zeichen inkl. des bei scanf immer terminierenden vorhandenen '\n' aus stdin, damit folgende stdin-Operationen keinen Schaden nehmen */
    

    Beachte die while-Schleife danach, die wird von 99% aller Tutorials/Bücher und 100% aller Anfänger hier im Forum ignoriert.

    Kann man die 19 durch eine Variable ersetzen ?



  • ja, mittels sprintf:

    char me[100];
    char s[20];
    sprintf(s, "%%%u[^\n]", sizeof(me)-1);
    scanf(s, me);
    

    Die drei % sind nötig, da mittels der ersten beiden das Prozentzeichen geschrieben wird und %u dann den Parameter auswertet.



  • Oder z.B. sowas machen:

    #include <stdio.h>
    
    #define STRSIZE 20
    #define SCNSTR "19"
    
    void f() {
      char me[STRSIZE];
      scanf("%" SCNSTR "s", me);
      // ...
    }
    

  • Mod

    edit: Hier stand Unsinn.



  • SeppJ: was willst du mir damit sagen?
    Es geht hier darum einen Formatstring für scanf zu erzeugen, nicht einen String auszugeben...



  • @Th69: Dein Vorschlag ist falsch weil du sprintf falsch benutzt.

    Da das Problem mit variabler Größe für ein sicheres Einlesen von C-Strings ja wohl doch etwas schwierig zu sein scheint, hier mal der Ausbau meiner o.g. Variante diesbezüglich:

    enum {SLEN=20};
    char me[SLEN]; /* Definition von Speicherplatz für einen max. 19 Zeichen langen C-String */
    printf("Wie heissen sie?");
    {
      char ftmp[40];
      sprintf(ftmp,"%%%d[^\n]",SLEN-1);
      scanf(ftmp, me); /* liest max. 19 Zeichen, '\0' wird immer angehängt */
    }
    while( getchar()!='\n' ); /* leert alle nicht gelesenen Zeichen inkl. des bei scanf immer terminierenden vorhandenen '\n' aus stdin, damit folgende stdin-Operationen keinen Schaden nehmen */
    

    Und für ständigen Gebrauch packt man das ist eine Funktion:

    char *liesStr_(char *s,int n)
    {
      char ftmp[40];
      sprintf(ftmp,"%%%d[^\n]",n-1);
      if( scanf(ftmp, s)!=1 ) return 0;
      while( getchar()!='\n' );
      return s;
    }
    
    #define liesStr() liesStr_((char[100]){0},100)
    
    ...
    char *str1 = liesStr();
    ...
    char *str2 = liesStr();
    ...
    puts(str2);
    ...
    puts(str1);
    

    Wegen automatic storage duration des compound literals sollte man aber die "Default" Größe im Makro nicht unnötig hoch ansetzen.



  • Oder man benutzt doch einfach fgets... 🙄



  • scanf("%*s", size, string);
    

    Nein, das geht so nicht.


  • Mod

    Wutz schrieb:

    scanf("%*s", size, string);
    

    Nein, das geht so nicht.

    Oh, stimmt. Ich lösch das mal, bevor es noch jemand übernimmt.



  • OK, habe den ersten Parameter vergessen 😞
    Habe den Beitrag daher nacheditiert...



  • Wutz schrieb:

    enum {SLEN=20};
    char me[SLEN];
    

    Welchen Vorteil bringt es die 20 als enum zu initialisieren und nicht als #define?


  • Mod

    Mz schrieb:

    Welchen Vorteil bringt es die 20 als enum zu initialisieren und nicht als #define?

    #define (und ebenso fast jede andere Präprozessoranweisung) ist eine globale Textersetzung durch den Präprozessor, die vor der Übersetzung des Programms stattfindet (daher der Name Präprozessor) und sich entsprechend an keine Regel der Sprache C hält. Ein enum ist hingegen ein Feature der Sprache C und bei der Übersetzung des Programms wird von dem enum die Struktur logische des Programms respektiert. In erster Linie, heißt dies, dass das enum einen Gültigkeitsbereich hat, auf den es beschränkt ist. Also kann es keine bösen Überraschungen geben, wenn irgendwo ganz woanders im Programm das Wort "SLEN" vorkommt und dieses dann vom Präprozessor ersetzt wird.


Anmelden zum Antworten