Array einen Wert zuweisen!!



  • Hallo Leute !

    ich hoffe Ihr könnt mir helfen. Ich habe folgendes Problem:
    Ich möchte in ein zweidimensionales Array Wörter speichern.
    Nur soll wenn q eingegeben wird das Programm abbrechen, und wenn nicht soll der Wert der eingelesen wird in das Array gespeichert werden.

    Bei Eingabe von q bricht das Programm auch Ordnungsgemäß ab.
    Nur wenn nicht q ein gegeben wird soll er es ins Array schreiben.

    Das Programm soll nur abbrechen wenn q eingegeben wird. Wenn ich beispielsweise: Quark eingebe bricht es auch ab.

    Frage 1:
    Nun die Konkrete Frage: Wie kann ich im else Zweig den Wert von scanf ins Array schreiben lassen?

    Frage 2:
    Wie muss der Befehl lauten, dass er nur bei Eingabe von q abbricht und nicht wenn man ein Wort eingibt das mit q anfägt.

    Bitte um Rücksicht, dass die Aufgabenstellung ist ein Zweidimensionales Array zu benutzen.

    Ich freu mich auf eure Antworten.

    Beiliegend hoch mein Quellcode.

    char eingabe;
    char arr[9][25];
    .
    .
    .
    for(i = 0; i < 10; i++ )
    {
    printf("Eingabe:\n");
    printf("Wort # %d \t:",i+1);
    scanf("%s", &eingabe);

    if (eingabe == 'q')
    {
    break;
    }
    else
    {
    eingabe = arr[i][];
    }
    }

    Option: Ich wollte das ganze auch mit folgendem Befehl machen allerdings war dies auch erfolglos 😞

    do
    {
    scanf("%d", &eingabe);
    }
    while (getchar() != 'q');



  • %s und char passen nicht zusammen, denn %s erwartet einen Zeiger auf einen Speicherbereich, der genug Platz hat.

    Mach aus eingabe auch ein Array. (am besten auch für 25 Zeichen.
    Den Vergleich mit "q" musst du dann mit strcmp machen.



  • char eingabe[25];
    char arr[9][25];
    .
    .
    .
    for(i = 0; i < 10; i++ )
    {
    printf("Eingabe:\n");
    printf("Wort # %d \t:",i+1);
    scanf("%s", eingabe);

    if (eingabe == 'q')
    {
    break;
    }
    else
    {
    eingabe = arr[i][];
    }
    }

    So ich habe das mal geändert aller dinge funktioniert das speichern im Array immer noch nicht. Ich habe ein bisschen Probleme bei der Durchführung 🙂



  • Zum einen schrieb ich etwas von strcmp.
    Achte dabei auch suf due "

    Zuweisen von Arrays geht in C nicht mit dem =

    Selbst wenn, wäre bei dir die Reihenfolge vertauscht. (es wäre Ziel=Quelle)

    Für Strings ist dafür strcpy vorgesehen.



  • if (eingabe[0] == 'q') wäre korrekt um das 1. Zeichen der Eingabe zu prüfen.
    Damit das wort quark auch geht
    if ((eingabe[0] == 'q') && (eingabe[1] == '\n')) ...
    ansonsten die daten mit strcopy ins array und
    das gnu c-programming tutorial durcharbeiten so wie ich das mache..



  • Als ebenfalls C-Neuling nutze ich die Aufgabenstellung mal als Übung und als Möglichkeit, meine Lösung von den Cracks hier korrigieren lassen. 🙂

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define LIMIT 20
    
    int main()
    {
      // declarations                                                                                                                                                                    
      char **str = malloc(0); if (NULL == str) return EXIT_FAILURE;
      char tmp[LIMIT];
      short i = 0, j;
      size_t cTmp;
    
      // read                                                                                                                                                                            
      do {
        // read into tmp                                                                                                                                                                 
        fgets(tmp, LIMIT, stdin);
        cTmp = strlen(tmp) - 1; // - \n                                                                                                                                                  
    
        // copy to str                                                                                                                                                                   
        str = realloc(str, (i + 1) * sizeof(*str)); if (NULL == str) return EXIT_FAILURE;
        str[i] = malloc(cTmp + 1); /* + \0 */ if (NULL == str[i]) return EXIT_FAILURE;
        strncpy(str[i], tmp, cTmp);
    
        i++;
      } while (strcmp(tmp, "q\n"));
    
      // write                                                                                                                                                                           
      printf("---\n");
      for (j = 0; j < i; j++)
        printf("%s\n", str[j]);
    
      return EXIT_SUCCESS;
    }
    


  • malloc(0) ist nicht nötig. char **str = NULL; ist ausreichend, da realloc sich wie malloc verhält, wenn der erste Paramter NULL ist.
    (str ist übrigens ein blöder Name dafür)

    Das -1 beim strlen ist überflüssig, da du es beim malloc wieder dazu packst.
    Zudem ist kein '\n' im String, wenn du mehr als LIMIT-2 Zeichen eingibst.

    Das größte Problem ist aber das strncpy .
    Du kopierst weniger Zeichen als in tmp drin sind (da ist noch das '\n' am Ende)
    In diesem Fall hängt strcpy keine '\0' an den String.

    Eine Lösung: Mit strrchr nach dem '\n' suchen und die Fundstelle durch das '\0' ersetzen.

    Ach ja, das "q" sollte wohl nicht mit abgespeichert werden.



  • Vorsicht es kann auch immer gelten (kommt auf die Implementierung an)

    malloc(0) == NULL
    


  • Dirk, danke für den Tipp, dass realloc sich bei NULL wie malloc verhält, so wie ich das hatte, hat mir das auch nicht gefallen.
    Der Nul-Byte-Fehler ist allerdings erschreckend.
    Ist das ok, wenn ich einfach folgendes mache, oder ist das ein schlechter Stil oder sogar falsch?

    *strrchr(tmp, '\n') = '\0';
    


  • DirkB schrieb:

    Zudem ist kein '\n' im String, wenn du mehr als LIMIT-2 Zeichen eingibst.

    strrchr schrieb:

    Return Value
    A pointer to the last occurrence of character in str.
    If the character is not found, the function returns a null pointer.

    Dann kannst du auch gleich gets nehmen 🤡

    Nein, lass das sein. Das war ein schlechter Scherz.



  • Danke für deine Zeit und Mühe.



  • ...und alle Zeichen, die ich mehr als LIMIT - 2 eingebe bleiben im Stream hängen und füllen automatisch den nächsten Wert des Arrays auf. Jürgen Wolf empfiehlt mir folgendes:

    fgets(tmp, LIMIT, stdin); while (fgetc(stdin) != '\n');
    

    Wie löst ihr sowas?



  • rednaZ schrieb:

    Jürgen Wolf empfiehlt mir folgendes:

    ...und ich empfehle dir, dir ein anderes Buch zuzulegen. Von jemandem, der C kann. Der Code, den du da hast, wird, wenn die Zeile kurz genug ist, um vollständig in den Buffer zu gehen (also im Normalfall), die nächste Zeile ignorieren.

    Was die Problemstellung angeht, so gibt es da verschiedene Herangehensweisen, abhängig davon, was für ein Verhalten du willst und wie wichtig Performance/Speicher sind. Wenn du den Rest der Zeile ignorieren willst und Performance keine Rolle spielt (das ist bei Benutzereingaben der Fall -- es steht nicht zu erwarten, dass man dir da gigabyteweise Daten in einem Tempo unterschiebt, dass du nicht mehr hinterherkommst), ist

    if(fgets(buf, BUFSIZE, stdin) &&
       buf[strlen(buf - 1)] != '\n')
    {
      while(fgetc(stdin) != '\n')
        ;
    }
    

    eine Möglichkeit. Wobei du dann in einem Fall einen String hast, der auf '\n' endet und einmal nicht, und wobei du natürlich Benutzereingaben teilweise verlierst. Performancemäßig ist das vor allem deshalb nicht so prall, weil fgetc jedes mal den Stream lockt, aber das dürfte in deinem speziellen Fall nicht so das Problem sein.

    Wenn du GNU-Funktionen verwenden kannst, gibt es in der glibc eine Funktion getline, die das Problem ziemlich hübsch mit dynamischem Speicher löst. Das sieht etwa so aus:

    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void) {
      char *line = NULL;
      size_t buflen = 0;
    
      while(getline(&line, &buflen, stdin) && 0 != strcmp(line, "exit")) {
        puts(line);
      }
    
      free(line);
    }
    

    getline fordert ausreichend Speicher an, um die Zeile aufzunehmen, und verwendet bei zukünftigen Durchläufen den Buffer wieder bzw. realloct sich einen größeren. Wenn du unter Linux unterwegs bist und dein Code vorläufig nicht anderswo laufen muss, ist das der bequemste Ansatz.

    Ansonsten hab ich hier noch etwas alten Code rumliegen, der für den Zweck auch gehen sollte:

    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *get_line(FILE *stream) {
      size_t const CHUNKSIZE = 128;
    
      size_t n = 0;
      char *buf = NULL, *pos = NULL;
    
      if(feof(stream)) return NULL;
    
      do {
        char *p;
    
        n += CHUNKSIZE;
    
        p = realloc(buf, n + 1);
        if(p == NULL) {
          free(buf);
          return NULL;
        }
        buf = p;
        pos = buf + n - CHUNKSIZE;
    
        if(fgets(pos, CHUNKSIZE + 1, stream) == NULL) {
          if(n > CHUNKSIZE && feof(stream)) {
            return buf;
          } else {
            free(buf);
            return NULL;
          }
        }
      } while(pos[strlen(pos) - 1] != '\n');
    
      return buf;
    }
    

    Diese Funktion erhöht nach und nach die Länge des Buffers, bis die Zeile in ihn hineinpasst. Im Gegensatz zu getline benutzt sie einen alten Buffer aber nicht wieder und lässt (wie fgets) das \n am Ende des Strings, so dass die benutzende Schleife in dem Fall beispielsweise so aussähe:

    char *line;
    int keep_going = 1;
    
    while(keep_going && (line = get_line(stdin)) != NULL) {
      if(strcmp(line, "exit\n") == 0) {
        keep_going = 0;
      } else {
        puts(line);
      }
    
      free(line); // jede Zeile muss freigegeben werden, nicht nur einmal
                  // der dauernd wiederbenutzte Buffer.
    }
    

    Das ist im Vergleich zu getline suboptimal, aber wenn du keinen Zugriff auf GNU hast vertretbar.


Anmelden zum Antworten