Pointer Arrays in C



  • Hallo,
    da ich demnächst wieder einiges in C arbeiten muss, versuche ich mich gerade wieder ein bisschen damit zu spielen. Und wieder hänge ich da wo ich vor Jahren aufgehört habe: Pointer Arrays.

    Folgendes Problem:

    Ich definiere eine struct.

    typedef_struct struct_point
    {
      int x;
      int y;
    } point_t;
    

    Jetzt will ich eine Methode schreiben, die in etwa so aussehen soll:

    int generate_random_polygon(point_t **polygon, int vertices)
    {
      point_t *polygon = (point_t*)malloc(vertices * sizeof(point_t));
      if (polygon)
      {
        for (int i = 0; i<vertices; i++, polygon++)
        {
          polygon->x = 0; // Zufallszahl!!
          polygon->y = 0; // Zufallszahl!!
        }
        return 0;
      }
      else 
      {
        return -1;
      }
    }
    

    Dabei stellen sich mir folgende Fragen:

    • wie muss der Funktionsparameter polygon aussehen, damit er als point_t array behandelt wird (Zeile 1)
    • wie kann ich darüber iterieren? (Zeile 6)
    • wie kann ich in anderen funktionen darüber iterieren (wenn ich vertices nicht mehr kenne)
    • wie kann ich das array als caller wieder freigeben?

    Bitte um Hilfe.

    mfg, guni


  • Mod

    Alle Fliegen mit einer Klappe:

    typedef struct
    {
      // Was immer du an Nutz- und Verwaltungsdaten benoetigst
    } Polygon;
    
    Polygon construct_polygon( /*evtl. Parameter*/)
    {
      // erstellt ein Polygon, d.h. holt dynamisch Speicher usw.
    }
    
    void destruct_polygon(Polygon p)
    {
      // Gibt das Ding wieder sauber frei
    }
    
    void tu_was_nuetzliches_mit_polygon(Polygon p)
    {
      // was auch immer
    }
    
    // bei Bedarf auch noch: - Erstellen eines Polygons als Kopie eines anderen
    //                       - Zuweisen eines Polyogns an ein anderes
    // und natuerlich alle anderen Nutzfunktionen, die du brauchst
    
    int main()
    {
      Polygon p = construct_polygon();
      tu_waS_nuetzliches_mit_polygon(p);
      destruct_polygon(p);
    }
    

    Gegebenenfalls bietet es sich auch an, noch eine weitere Indirektion einzufuehren, das heisst, der Handler ist nur noch ein Zeiger auf das Polygon, nicht mehr das Polygonobjekt selbst. Das hat auch den Vorteil, dass man die Defintion des Polygons dann vor dem Nutzer verstecken kann, so dass die Kapselung komplett wird.



  • Servus SeppJ,

    danke für deine Antwort. Leider hilft mir das nicht wirklich weiter. Du schlägst mir vor, welche Funktionen ich erzeugen soll. Deine Idee finde ich gut, da es ziemlich nahe an der Objektorientierung ist. Mein Problem mit dem Pointerverständnis ist damit allerdings noch gar nicht behoben.

    mfg, guni



  • typedef_struct struct_point
    {
      int x;
      int y;
    } point_t;
    

    Das compiliert nicht.

    int generate_random_polygon(point_t **polygon, int vertices)
    {
      point_t *polygon = (point_t*)malloc(vertices * sizeof(point_t));
    

    Das compiliert auch nicht.

    • ein an eine Funktion direkt übergebenes Array zerfällt immer in einen Zeiger auf das erste Arrayelement (egal wie du deklarierst)
    • mit dem subscript operator []
    • gar nicht, weil du keine (Array)Größeninformation besitzt, wenn du diese nicht zusätzlich übergibst
    • ein Array(Speicherbereich) kannst du nicht wieder freigeben, es existiert solange, wie sein Sichtbarkeitsbereich gültig ist

    Üblicherweise übergibt man die Größeninformation für ein Array separat oder für dynamischen Speicher zusammen als struct,

    typedef struct{int a,b;} Typ;
    typedef struct{ int n;Typ *elemente; } Liste;
    
    /* Array */
    int funktion(Typ elemente[],int n)
    {
      while( n-- ) elemente[n].a = 0;
      ...
    }
    enum {EZAHL=100};
    Typ elemente[EZAHL];
    funktion(elemente,EZAHL);
    
    /* dynamischer Speicher */
    int funktion(Liste liste)
    {
      int i;
      for(i=0;i<liste.n;++i)
        liste.elemente[i].a=0;
      ...
    }
    Liste liste={100};
    liste.elemente=calloc(liste.n,sizeof*liste.element);
    funktion(liste);
    ...
    free(liste.elemente);
    


  • Hallo Wutz,

    danke für deine Antwort. Du schreibst

    ein Array(Speicherbereich) kannst du nicht wieder freigeben, es existiert solange, wie sein Sichtbarkeitsbereich gültig ist

    Trotzdem finde ich in deinem Code ein "free". Wie kann ich das verstehen? m.W. muss man alles was auf dem Heap liegt wieder aufräumen. Und ein Array ist in C ja eigentlich das gleiche wie eine Menge von Pointern; d.h. einige Werte auf dem Heap. Irgendwie muss ich die alle wieder loswerden, oder ...

    Und verstehe ich das richtig, dass der einzige Unterschied zwischen malloc und calloc die Initialisierung mit 0 is?

    mfg, guni



  • guni schrieb:

    Und ein Array ist in C ja eigentlich das gleiche wie eine Menge von Pointern; d.h. einige Werte auf dem Heap.

    Nein.

    Ein Speicherbereich, den du mit malloc besorgst und (dessen Anfangsadresse du) einem Pointer zuweist, mag sich teilweise wie ein Array verhalten. Es ist aber keins.
    Und der Heap oder Stack ist dem C-Standard völlig egal. Kennt der nicht.

    Für einen Speicherbereich brauchst du einen Pointer. Willst du mehrere Speicherbereiche vorhalten, dann brauchst du mehr Pointer. Die kannst du dann in einem Array zusammen fassen.

    Für dein Beispiel (eine Menge an Elementen), reicht ein Array/Speicherbereich aus.

    Dein Beispiel mit einem typedef, das das Wort point enthält ist für die Begrifflichkeit mit Pointern eher störend.

    guni schrieb:

    Und verstehe ich das richtig, dass der einzige Unterschied zwischen malloc und calloc die Initialisierung mit 0 is?

    Die Parameter sind noch verschieden.


  • Mod

    guni schrieb:

    Und verstehe ich das richtig, dass der einzige Unterschied zwischen malloc und calloc die Initialisierung mit 0 is?

    Von dem, was es letztendlich tut her: Ja. Aber denk dran, dass der Aufruf auch ein bisschen anders ist (Anzahl und Einzelgröße statt Gesamtgröße als Parameter).

    Trotzdem finde ich in deinem Code ein "free". Wie kann ich das verstehen? m.W. muss man alles was auf dem Heap liegt wieder aufräumen.

    Korrekt.

    Und ein Array ist in C ja eigentlich das gleiche wie eine Menge von Pointern; d.h. einige Werte auf dem Heap.

    Nein, nein, nein! Immer der gleiche Fehler. Array != Pointer. Pointer != Etwas auf dem Heap*. Pointee+ != Etwas auf dem Heap.

    Das sind ganz unterschiedliche Sachen.

    *: Oder Freispeicher, wenn wir streng im Standardsprech bleiben wollen.
    +: Etwas, auf das ein Zeiger zeigt.



  • guni schrieb:

    Trotzdem finde ich in deinem Code ein "free".

    Wieso trotzdem?
    In dem Array-titulierten Teil steht nirgendwo ein free, weil man ein Array nicht freigeben kann und darf.
    In dem anderen Teil kommt nirgendwo ein Array vor, dafür aber calloc, und das verlangt ein free.
    Probiere doch mal aus, was dein Compiler zur Freigabe eines Arrays mit free sagt:

    #include <stdlib.h>
    int main()
    {
      int array[100];
      free(array);
      return 0;
    }
    

    http://ideone.com/n7sOb1

    Dasselbe Problem tritt auf, wenn man den Zeiger zwischen malloc und free verändert, und 'vergisst', dass free nur auf dem Originalzeigerwert bei malloc korrekt arbeitet.

    Wenn du das Array durch Übergabe an eine Funktion 'verschleierst', kann der Compiler sowas nicht mehr finden, (verbreitete Unsitte bei Anfängern, Buchautoren, Hochschullehrern, dem Compiler jegliche Möglichkeit zur Warnung zu nehmen, z.B. durch Casts) und erst das Laufzeitsystem weist dich auf die Unmöglichkeit, den Speicherbereich eines Arrays explizit freizugeben hin:

    #include <stdlib.h>
    void freigabe(int array[100])
    {
    free(array);
    }
    
    int main()
    {
    int array[100];
    freigabe(array);
    return 0;
    }
    

    http://ideone.com/MZL4QA


Log in to reply