Array von Structure in Funktionen verändern



  • Hallo!

    Vorweg: Ich bin noch nicht wirklich erfahren mit C (hab bisher vor allem mit Pascal programmiert).

    Problem:
    Ich hab eine Structure für X, Y, Z Koordinaten von der ich 6 Stück brauche. Zum einfacheren Handhabung habe ich mir gedacht, mache ich ein Array von dieser Struktur. Alles funktioniert tadellos, jetzt stehe ich allerdings vor dem Problem, dass ich einige Dinge aus der main Funktion auslagern möchte (sprich in eigene Funktionen packen möchte). Diese Funktionen sollten die X, Y, Z Koordinaten des Arrays verändern und dieses dann wieder zurückgeben. Jetzt bin ich allerdings draufgekommen, dass ich keine Arrays aus einer Funktion zurückgeben kann.

    Für mich stellen sich jetzt 3 Lösungswege, wobei ich allerdings nicht weiß welcher der sauberste, schnellste, leistungsschonenste ist. Laufen wird das ganzen auf einem AVR Mikrokontroller zur Ansteuerung von 6 Beinen (Hexapod).

    a) Das Array global machen und direkt in den Funktionen verändern (ohne Wertübergabe).
    Ich hab allerdings immer im Hinterkopf, dass globale Variablen schlecht sind (sehr extrem böse wenn möglich immer und überall vermeiden). Mir ist allerdings nicht klar warum das so ist und ob dies nicht einer dieser Ausnahmefälle ist.

    b) Eine Struktur erstellen die ein Array von der Koordinatenstruktur enthält.
    Funktioniert auch tadellos, aber wird dann nicht bei jeder Funktionsaufruf eine Kopie der Werte erstellt und hin und wieder zurückverschoben. Das ganze würde sehr ineffizient sein (außer der Compiler ist intelligent genug und optimiert so etwas).

    c) Wie b, nur dass anstatt einer Wert hin und Rückgabe nur ein Pointer übergeben wird. Hab noch nicht so viel Erfahrungen mit Pointern und leider funktioniert dieser Ansatz noch nicht. (Fehler: "request for member ‘leg’ in something not a structure or union").

    Gibts da noch bessere Ansätze oder sollte man das ganze komplett anders machen?

    Danke für eure Hilfe,

    schneida



  • Hallo,

    (c) ist der naheliegende Weg. Hättest du für deinen Fehler dort gleich Code gezeigt, müsste ich jetzt wahrscheinlich nicht so viel schreiben, und hoffen, dass ich verstanden habe, wie wohl die Strukturen und das Array aussehen. Deswegen hier ein Versuch:

    Es liegt vor:

    struct coord {
      int x;
      int y;
      int z;
    }
    

    irgendwo wird dieser Typ dann in einem Array mit 6 Elementen benutzt:

    struct coord a[6];
    

    die Funktion, die ein solches Array entgegen nehmen könnte, heisse test, gebe nichts zurück, und wird so (z.B. in main) aufgerufen:

    test(a);
    

    und innerhalb von Test greift man auf die Strukturen bzw. deren Mitglieder so zu:

    void test (struct coord coords*)
    {
       // Koordinaten von Struktur an erster Arrayposition aendern
       coords[0].x = 4;
       coords[0].y += 4;
       coords[0].z = coords[0].x;
    
    }
    

    MfG,

    Probe-Nutzer



  • Hey danke! Funktioniert jetzt:

    #include <stdio.h>
    
    typedef struct IK_Point3d
    {
        int X;
        int Y;
        int Z;
    } IK_Point3d;
    
    void test (IK_Point3d *legg)
    {
    int i;
    	for (i=0; i<6; i++)
    	{
    		legg[i].X = 0;
    		legg[i].Y = 70;
    		legg[i].Z = 65;
    	}
    	legg[3].X = 72;
    }
    
    int main()
    {
    	IK_Point3d legs[6];
    	int i;
    
    	test(legs);
    
    	for (i=0; i<6; i++)
    	{
    		printf("X: %d; Y: %d; Z: %d\n", legs[i].X, legs[i].Y, legs[i].Z);
    	}
    	return 0;
    }
    

    Wie schon gesagt bin ich mit Pointer nicht ganz so gut, aber wieso hast du den Stern in der Funktionsdefinition hinter den Parameter und ich musste ihn davor setzen?

    Auf alle Fälle danke für die schnelle Antwort

    schneida



  • aber wieso hast du den Stern in der Funktionsdefinition hinter den Parameter und ich musste ihn davor setzen
    

    nobodys perfect oder?



  • Ok, das heißt Stern vorne ist richtig und erzeugt nicht gleich irgendwelche verborgene Fehler.



  • ja so hätte man das auch sagen können 😉



  • schneida schrieb:

    void test (IK_Point3d *legg)
    {
    int i;
    for (i=0; i<6; i++)
    {
    legg[i].X = 0;
    legg[i].Y = 70;
    legg[i].Z = 65;
    }
    legg[3].X = 72;
    }

    geht das ganz sicher ?
    normal greift man auf einen strukturpointer ja so zu:

    (legg+i)->X=0;...
    

    oder täusche ich mich da ??



  • also soweit ich weiß ist

    *(ptr+1) == ptr[1]
    *(ptr+2) == ptr[2]
    ....
    
    sowas sollte dann also auch gehen
    void test (IK_Point3d *legg) 
    void test (IK_Point3d legg[])
    


  • ja ist eh nicht so wichtig, wenns anders auch geht...
    ich machst halt immer mit dem pfeiloperator wenn ich auf ein element einer struktur zugreife, die ein pointer ist...



  • Hi!
    Variante a kann auch ganz ok sein, wenn z.B. die Variable/das Array, was auch immer, während der gesamten Programmdauer leben soll oder wenn es nicht so auf ein paar Bytes drauf ankommt. Wäre also schonmal keine Speicherplatzverschwendung, der Code ist geringfügig effizienter denn das Array braucht keinen Stack, es entfallen u.U. etliche Funktionsparameter, durch die der Zeiger/das Array durchgeschliffen werden müsste, die Codeentwicklung ist weniger nervig, man ist schneller fertig, Programm ist leichter lesbar/wartbar.
    Kann also ne menge Arbeit sparen und Vorteile mit sich bringen.

    Schreibst du noch ein static davor, dann hast du das Array vor Eingriffen von außen geschützt. Nur die Funktionen der Datei, in der das Array definiert ist, dürfen die Variable verändern.
    Aus der OOP Sicht könnte man sagen, deine *.c Datei ist die Klasse, die deine private static Variable kapselt.
    Sieh das doch als Vorteil, das du da nicht extra ein public class xyz drum herum bauen musst.

    Gruß,
    B.B.



  • weiß nicht ob es einen großen unterschied macht aber wenn du i immer um eins erhöhst ist evtl. die 2. variante etwas schöner dann sparst du dir die klammern usw...

    for (...)
    {
        (legg+i)->X = 65;
        (legg+i)->Y = 65;
        (legg+i)->Z = 65;
    } 
    
    for (...)
    {
        legg->X = 65;
        legg->Y = 65;
        legg->Z = 65;
        legg++;
    }
    

    lg lolo



  • @edolver: Also den Code den ich oben gepostet habe, der funktioniert ganz sicher (zumindest mit gcc 4.4).

    @BigBrother: Wo liegen dann die Nachteile von globalen Variablen und wieso sind sie sooooo verhasst? Weil mittels eines Pointers zugreifen (so wie oben im Code Beispiel) ist ja auch nicht soo toll, weil ich, wenn ich nur den Funktionsaufruf sehe, nicht erkennen kann, dass die Funktion meine Parameter verändert. Das ist so ziemlich der einzige Nachteil den ich bei globalen Vars sehe.



  • schneida schrieb:

    sooooo verhasst

    ist evtl. ein bischen übertrieben, auch sollen sie das ein oder andere programm etwas schneller machen, aber stell dir mal vor du hast 10 globale vars und auf die wird von 10 verschiedenen functionen aus zugegriffen dann hast schonmal ein problem da den überblick zu behalten, wär auch möglich das fork() bzw. pthread() globale variablen nicht so gern mögen??



  • Naja aber auf die Pointer-Variablen wie ich sie jetzt verwende wird ja auch "global" zugegriffen, sprich ich sehe halt das ich den Pointer übergebe, aber ob sie verändert werden erfahr ich nicht sofort.

    Gut ich denke ich bleib aber jetzt bei der Pointer Variante, schnell, lesbar, sauber. Was will ich mehr 🙂

    Danke nochmals für eure Hilfe!


Anmelden zum Antworten