C Dynamisches Array



  • Moin!

    Beim Surfen im Internet bin ich auf das unten stehende Programm gestoßen und wollte mal einpaar Ideen bzw. einpaar Fragen dazu hier schreiben.

    Da ich etwas Erfahrung bzw noch relativ am Anfang bei C bin habe ich folgende Fragen:

    - Wenn ich eine Funktion haben möchte, die als Parameter (int Array, int eintrag, int fehler) hat.
    Das Array soll immer beim Aufruf das Array um einen Index erweitert werden und den (neuen) Eintrag in die neuen Index schreiben.
    Wenn dies einen Fehler verursacht (kann keinen Speicher reservieren, etc) soll dies in der Variable "fehler" zurück geben werden.

    Dafür muss ich noch den Code in eine Funktion verschieben mit den drei Paramter, die zu (int *Array, int *eintrag, int *fehler) werden, schreiben?

    Und den Code muss ich bei dem Code folgendes ändern:

    - Größe gleich alte Größe+1
    - Eingabe = eintrag;
    - und eventuelle Fehler in den 3. Parameter schreiben oder?

    /* dyn_array3.c */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(void) {
       int *value,*temp;
       int i=0, more;
       int size, merker = 0;
    
       printf("Wie viele Werte benötigen Sie : ");
       scanf("%d", &size);
       value = (int *)malloc(size*sizeof(int));
       if(NULL == value) {
          printf("Fehler bei malloc...!! n");
          return EXIT_FAILURE;
       }
       do {
          while(merker < size) {
             printf("Wert für value[%d] eingeben : ",merker);
             scanf("%d",&value[merker]);
             merker++;
          }
          printf("Neuen Platz reservieren (0=Ende) : ");
          scanf("%d",&more);
          temp = malloc(size*sizeof(int));
          if(NULL == temp) {
             printf("Kann keinen Speicher mehr reservieren!\n");
             return EXIT_FAILURE;
          }
          for(i=0; i<size; i++)
             temp[i]=value[i];
          size+=more;
          value = malloc(size * sizeof(int));
          if(NULL == value) {
             printf("Kann keinen Speicher mehr reservieren!\n");
             return EXIT_SUCCESS;
          }
          for(i=0; i<size; i++)
             value[i]=temp[i];
       }while(more!=0);
       printf("Hier Ihre Werte\n");
       for(i=0; i<size; i++)
          printf("value[%d] = %d\n" ,i ,value[i]);
       return EXIT_SUCCESS;
    }
    

    Link:
    http://openbook.galileo-press.de/c_von_a_bis_z/014_c_dyn_speicherverwaltung_007.htm

    Danke und viele Grüße


  • Mod

    Ich verstehe nicht was deine Frage ist. Aber der Galileo-Verlag und insbesondere der Autor Jürgen Wolf sind hier alte Bekannte und du solltest einen weiten Bogen um alles machen, wo deren Namen drauf steht:
    www.c-plusplus.net/forum/272350

    Wahrscheinlich lösen sich sämtliche Probleme von alleine, wenn du mit guten Lehrbüchern arbeitest. Das was du von Herrn Wolf gelernt hast, solltest du hingegen möglichst schnell vergessen.

    Dein Beispielcode ist ein typischer Wolf:

    • Leckt 100% des Speichers.
    • Kennt nicht die wesentlich bessere Methode mittels realloc
    • Dicker Fehler in Zeilen 38-39, wo fröhlich hinter die Grenzen des Arrays zugegriffen wird.
    • ~Auch niedlich -- aber nur eine Randnotiz gegenüber den anderen Sachen -- ist, wie er einmal den Rückgabewert von malloc castet, ein anderes Mal nicht. Da weiß wohl jemand nicht so wirklich, was er da warum tut :)~
    • ~Das Yoda-if, auch erwähnenswert es ist. Angst er hat, vor den eigenen Fehlern.~
    • Andere Kleinigkeiten zähle ich lieber gar nicht auf, sonst bin ich morgen noch damit beschäftigt.

    Das sind zwei gewaltige Fehler und ein Fall von der Lehrer weiß nicht, wie es richtig geht. In einem (Möchtegern-)Lehrbuch! Von diesem Autor kann man höchstens lernen, wie es nicht geht. Aber das ist nur etwas für Profis, denn die Fehler des J. Wolfs sind für Anfänger nicht offensichtlich und daher um so gefährlicher. Obiger Code mag auf vielen Systemen funktionieren, da ein hinreichend gutartiger Speichermanager die beiden malloc-Blöcke direkt hintereinander anlegt und der Code insgesamt nicht komplex genug ist, dass da irgendwas dazwischen funkt. So denkt der Anfänger, das wäre irgendwie richtig. Und wundert sich dann über Abstürze und undefiniertes Verhalten, wenn er die gezeigten Techniken in eigenen Programmen benutzt. Ganz, ganz miese Sache ist das 😞 .



  • Deine Argumente für die Funktion sind nicht gut gewählt.

    Da fehlt die Größe und für den neuen Speicherort bzw. Fehler kann man den Rückgabewert der Funktion nehmen.



  • Wie würde denn die "verbesserete" bzw. deine (@DirkB) Version aussehen des Code?

    @SeppJ: Ich wollte folgende Aufgabe(n) der Funktion überlassen:

    - Wenn ein neuer Eintrag in das Array geschrieben soll, wird das Array um +1 erhöht.

    - In dem neuen "Index" ´(Platz) wird der Wert eingetragen

    - Wenn die Größe nicht reserviert werden kann, soll ein entsprechender Fehler zurück gegeben werden.

    Danke und Grüße



  • Ich hab den Link aus dem ersten Beitrag aufgemacht und da wird realloc schon erwähnt. Steht allerdings noch nicht zur Debatte.



  • user-12b34 schrieb:

    Wie würde denn die "verbesserete" bzw. deine (@DirkB) Version aussehen des Code?

    @SeppJ: Ich wollte folgende Aufgabe(n) der Funktion überlassen:

    - Wenn ein neuer Eintrag in das Array geschrieben soll, wird das Array um +1 erhöht.

    - In dem neuen "Index" ´(Platz) wird der Wert eingetragen

    Wie willst du in der Funktion die neue Größe bestimmen, bzw. woher kennst du den Index?

    user-12b34 schrieb:

    - Wenn die Größe nicht reserviert werden kann, soll ein entsprechender Fehler zurück gegeben werden.

    Wie zeigt z.B malloc diesen Fehler an?

    Denke daran, das der neue Speicherbereich an einer ganz anderen Stelle liegen kann und du somit der rufenden Funktion diese Adresse irgendwie mitteilen musst.



  • Mechanics schrieb:

    Ich hab den Link aus dem ersten Beitrag aufgemacht und da wird realloc schon erwähnt. Steht allerdings noch nicht zur Debatte.

    Und free scheint so wichtig zu sein, dass es dafür sogar zwei Paragraphen gibt.
    Allerdings nutzt der Autor auf der verlinkten Seite kein free. 😮



  • Mir geht es darum, Werte in ein Array zu schreiben. Dieses soll aus Speicherplatzgründen sich immer vergrößen, wenn ein neuer Wert hinein geschrieben soll.

    Tritt dabei ein Fehler auf, soll darauf reagiert werden (Anzeigen Fehler, etc.)

    Diese Aufgabe soll in eine Funktion untergebracht werden.

    Danke



  • user-12b34 schrieb:

    Mir geht es darum, Werte in ein Array zu schreiben. Dieses soll aus Speicherplatzgründen sich immer vergrößen, wenn ein neuer Wert hinein geschrieben soll.

    Tritt dabei ein Fehler auf, soll darauf reagiert werden (Anzeigen Fehler, etc.)

    Diese Aufgabe soll in eine Funktion untergebracht werden.

    Danke

    Dann zeig mal den Code von der Funktion und sag, wo du Probleme hast.
    Interaktion mit dem User ist nicht Aufgabe dieser Funktion.


  • Mod

    Dann machst du eine schöne Struktur mit einem Zeiger auf die Daten und einem Merker, wie viele Plätze in dem Array sind. Dann machst du eine Funktion, die das struct initialisiert (für beide Werte macht 0 Sinn, denn schönerweise ist ein realloc auf einen Nullzeiger das gleiche wie ein malloc), eine Funktion zum Anhängen eines Wertes (die dann realloc benutzt) und eine Funktion zum Freigeben des Arrays am Programmende. Wenn wir schon objektorientiert sind, dann auch noch eine Funktion für den Zugriff. Und da ich gerade zu viel Zeit hatte:

    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct
    {
      int *data;
      size_t size;
    } *dynamic_array;
    
    dynamic_array create_dynamic_array()
    {
      dynamic_array array = malloc(sizeof(*array));
      array->data = NULL;
      array->size = 0;
      return array;
    }
    
    void* append_to_dynamic_array(dynamic_array array, int value)
    {
      int *new_array = realloc(array->data, (array->size+1) * sizeof(*array->data));
      if (new_array)
        {
          array->data = new_array;
          new_array[array->size] = value;
          ++array->size;
        }
      return new_array;
    }
    
    void destroy_dynamic_array(const dynamic_array array)
    {
      free(array->data);
      free(array);
    }
    
    int get_from_dynamic_array(const dynamic_array array, size_t index)
    {
      return array->data[index];
    }
    
    size_t get_size_of_dynamic_array(const dynamic_array array)
    {
      return array->size;
    }
    
    int main()
    {
      dynamic_array my_array = create_dynamic_array();
      int value; 
      size_t i; 
    
      while(scanf("%d", &value) == 1)
        {
          if (!append_to_dynamic_array(my_array, value))
            {
              puts("Au weia! Kein Speicher mehr.");
            }
        }
    
      puts("Arrayinhalt:");
      for(i = 0; i < get_size_of_dynamic_array(my_array); ++i)
        printf("%d\n", get_from_dynamic_array(my_array, i));
    
      destroy_dynamic_array(my_array);
    }
    

    So macht man das in C halbwegs sauber. Ich hab's jetzt absichtlich relativ anfängerfreundlich gehalten (insbesondere sehr lange Bezeichner), aber gleichzeitig das Konzept möglichst konsequent durchgezogen. Ansonsten könnte man hier und da noch ein paar Details verbessern.

    Demonstration:
    http://ideone.com/dgAi8c

    PS: Das malloc im Konstruktor sollte natürlich noch auf Erfolg prüfen. Das überlasse ich dem geneigten Leser zur Übung, den Fehler und dessen Weiterleitung sauber zu implementieren. Irgendwie juckt es mich in den Fingern, da jetzt ein kleines Exceptionframework drumherum zu basteln (oder meinetwegen mit at_exit & Co.), aber dann entfernt man sich schnell von der Tauglichkeit als Beispiel für Anfänger 🙂 . Für ein Wolf-Opfer ist das Beispiel vermutlich jetzt schon schwer genug verständlich.



  • Danke für die hilfreichen Antworten



  • Kennt jemand ein gutes C Buch bzw. hat jemand Erfahrung mit den auf dieser Seite aufgezeigten Bücher?

    Danke


  • Mod

    Ist ja nur als wichtig markiert 🙄 :
    https://www.c-plusplus.net/forum/300567


Anmelden zum Antworten