Forum: PC-Programmierung 2D Array als Struct definiert und mittels Zeiger darauf zugreifen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von FastExperte (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Grüss Gott,

ich muss auf einem vorhandenen Code basierend meine Weiterentwicklung 
dran hängen.
Es geht darum, dass ich ein globales, zweidimensionales Array, mittels 
eines Pointers (Singleton) überschreiben möchte. Es ist mir aber nicht 
ganz klar, wie ich die einzelnen Elemente des Arrays ansprechen kann, 
bzw. Frage ist ob ich die Adresse der 2D Arrays überhaupt richtig 
zurückgebe.

Der Code entspricht nicht dem 100%, soll aber eine Vorstellung geben was 
ich meine;
#define DIM_1   2
#define DIM_2   2

typdef enum{
MEIN_ELEMENT_1 = 1,
MEIN_ELEMENT_2 =2
}meinEnum;


typedef struct{
uint32 uint32_variable,
sint32 sint32variable
meinEnum myEnum
}meinStruct;

meinStruct meinArray[DIM_1][DIM_2] = {
    {
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_1 },
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_2 }
    },
    {
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_1 },
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_2 }
};

//ich wollte hier die Adresse des Arrays übergeben
meinStruct * getMeinArray(void)
{
    return &meinArray; //bin mir nicht sicher was der ReturnWert sein soll
}

void setMeinArray (void)
{

 uint32 neuerWert = 200;
 meinStruct (*ptrMeinStruct)[DIM_2] = getMeinArray();
 
 //hier habe ich keinen Plant wie ich einzelne Strukturelemente des Arrays
 //ansprechen kann und diese überschreiben könnte, mein miserabler Ansatz    //unten
 ptrMeinStruct->[1][1].trigs = neuerWert;

}


von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Mit einem typedef gehts einfacher:
#include <assert.h>
#include <stdint.h>

#define DIM_1   2
#define DIM_2   2

typedef enum
{
   MEIN_ELEMENT_1 = 1,
   MEIN_ELEMENT_2 = 2
} meinEnum;

typedef struct
{
   uint32_t uint32_variable;
   int32_t sint32variable;
   meinEnum myEnum;
} meinStruct;

typedef meinStruct array_of_DIM_2_t[DIM_2];
meinStruct meinArray[DIM_1][DIM_2];

array_of_DIM_2_t * getMeinArray(void)
{
   return meinArray;
}

int main(void)
{

   array_of_DIM_2_t *ptrMeinStruct = getMeinArray();

   ptrMeinStruct[1][1].uint32_variable = 200;
   ptrMeinStruct[0][1].uint32_variable = 100;
   ptrMeinStruct[1][0].uint32_variable = 300;

   assert(200 == meinArray[1][1].uint32_variable);
   assert(100 == meinArray[0][1].uint32_variable);
   assert(300 == meinArray[1][0].uint32_variable);
}

Oliver

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
FastExperte schrieb:
> typedef struct{
> uint32 uint32_variable,
> sint32 sint32variable
> meinEnum myEnum
> }meinStruct;
>
> meinStruct meinArray[DIM_1][DIM_2] = {....

oder mit einfachen Zeigern arbeiten:

meinStruct* p=&meinArray[0][0];

meinStruct* temp=p;
for(size_t i=0; i<DIM1*DIM2; i++, temp++)                              
   printf("x: %d, y: %d\n", temp->x, temp->y);


von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> typedef meinStruct array_of_DIM_2_t[DIM_2];

Oder gleich das ganze array:
}
typedef meinStruct meinArray_t[DIM1][DIM2];

meinArray_t meinArray;

meinArray_t* getMeinArray(void)
{
    return &meinArray;
}

Und Zugriff mit:
meinArray_t* pointer = getMeinArray();

(*pointer)[1][1].uint32_variable = 200;

von FastExperte (Gast)


Bewertung
0 lesenswert
nicht lesenswert
hallo, danke für die Unterstützung, hat jetzt geklappt...
was mich noch ein bisschen verwirrt, der Rückgabewert von der get() 
Funktion, mal wird hier das Array mit dem Adressoperator übergeben, mal 
ohne. Den Adressoperator würde ich eher erwarten, wenn ich ein bestimmes 
Element des Arrays ansprechen möchte [i][j]. Und ohne den Adressoperator 
erwarte ich die Startadresse des ersten Elements übergeben zu 
bekommen...

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
FastExperte schrieb:
> hallo, danke für die Unterstützung, hat jetzt geklappt...
> was mich noch ein bisschen verwirrt, der Rückgabewert von der get()
> Funktion, mal wird hier das Array mit dem Adressoperator übergeben, mal
> ohne. Den Adressoperator würde ich eher erwarten, wenn ich ein bestimmes
> Element des Arrays ansprechen möchte [i][j].



> Und ohne den Adressoperator erwarte ich die Startadresse des ersten Elements
> übergeben zu bekommen...

Das ist ja auch so. Man muss sich nur klar sein, dass es in C 
mehrdimensionale Arrays in dem Sinne nicht gibt. Es ist einfach ein 
Array aus Arrays. Das erste Element des äußeren Arrays ist daher wieder 
ein Array.

Variante 1: Ein Zeiger auf das erste Element des äußeren Arrays:
typedef meinStruct array_of_DIM_2_t[DIM_2];

array_of_DIM_2_t * getMeinArray(void)
{
   return meinArray;
}
meinArray ist hier äquivalent zu &meinArray[0] - die Adresse des ersten 
Elements.

Variante 2: Ein Zeiger auf das erste Element des ersten Elements:
meinStruct* p=&meinArray[0][0];
Hier hat man einfach einen Zeiger auf ein Element des inneren Arrays. 
Dabei geht aber dann die zweite Dimension verloren, und man muss die 
passende Index-Berechnung selber machen. Es wird einfach wie auf ein 
"plattes" Array zugegriffen.

Und hier noch Variante 3: Ein Zeiger auf das Array selbst:
typedef meinStruct meinArray_t[DIM1][DIM2];

meinArray_t* getMeinArray(void)
{
    return &meinArray;
}
In dem Fall muss der Zeiger dann vor dem Zugriff eben ganz normal 
dereferenziert werden.

von FastExperte (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo, muss noch mal nach hacken...

Rolf M. schrieb:
> Variante 1: Ein Zeiger auf das erste Element des äußeren Arrays:

d.h. wenn ich hier den Zeiger inkrementiere, zeige ich dann auf das 2te 
Element der 1 Dimension ?
pointer[0][0] --> inc --> pointer[1][0] --> inc --> pointer[2][0]

Rolf M. schrieb:
> Variante 2: Ein Zeiger auf das erste Element des ersten Elements:

hier würde ich einfach alle Elemente nach eindander durchlaufen...
pointer[0][0] --> inc --> pointer[0][1]-->inc-->pointer[0][2]...bis 
pointer[2][2]

Rolf M. schrieb:
> Und hier noch Variante 3: Ein Zeiger auf das Array selbst:

wie verhält sich der Zeiger hier...?

von guest (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Man muss sich nur klar sein, dass es in C
> mehrdimensionale Arrays in dem Sinne nicht gibt.
Richtig.

Rolf M. schrieb:
> Es ist einfach ein Array aus Arrays
Nö, es sind im Endeffekt eindimensionale Arrays der Größe 
DIM1*DIM2*...*DIMn.

Und genau so kann man auch darauf zugreifen:
array[x][y] == array[x*DIM2+y]
array[x][y][z] == array[x*DIM2*DIM3+y*DIM3+z]
...

Außerdem liefert der Name des Array die Addresse des Arrays, welche die 
Addresse des ersten Elemnts ist. Also für den Code aus dem ersten Post:
meinArray == &meinArray == &meinArray[0][0]
Alles vom Typ meinStruct*

Dazu kommt noch:
array[x] == *(array+x)

Um auf den Ursprungspost zurückzukommen:
meinStruct * getMeinArray(void)
{
    return meinArray;
}

void setMeinArray(void)
{
    uint32 neuerWert = 200;
    meinStruct * array = getMeinArray();
    array[1][1].uint32_variable = neuerWert;
    array[0][1].sint32variable = 400;
    array[1][0].myEnum = MEIN_ELEMENT_2;
    getMeinArray()[0][0].uint32_variable = 99;
}

von guest (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Noch ne Variante:
    (*getMeinArray()).uint32_variable = 88;
    // entspricht meinArray[0][0].uint32_variable = 88;

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
guest schrieb:
> meinArray == &meinArray == &meinArray[0][0]
> Alles vom Typ meinStruct*

Nein, der Datentyp ist bei allen unterschiedlich.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
guest schrieb:
> Rolf M. schrieb:
>> Es ist einfach ein Array aus Arrays
> Nö, es sind im Endeffekt eindimensionale Arrays der Größe
> DIM1*DIM2*...*DIMn.

So liegen sie im Speicher, aber sie sind nicht das selbe.

> Und genau so kann man auch darauf zugreifen:
> array[x][y] == array[x*DIM2+y]

Nein, das kann man so nicht. Man muss zwei Indizes angeben, sonst gibt 
es einen Fehler, weil der Typ nicht stimmt.

> Außerdem liefert der Name des Array die Addresse des Arrays, welche die
> Addresse des ersten Elemnts ist.

Stimmt auch nicht. Die Speicherstelle, auf die verwiesen wird, ist zwar 
die selbe, aber der Typ ist unterschiedlich.

> Also für den Code aus dem ersten Post:
> meinArray == &meinArray == &meinArray[0][0]
> Alles vom Typ meinStruct*

Nein, die Typen sind alle drei unterschiedlich. Nur das dritte ist vom 
Typ meinStruct*.

> Dazu kommt noch:
> array[x] == *(array+x)

Das ist zwar richtig, hier aber eigentlich nicht relevant.

> Um auf den Ursprungspost zurückzukommen:
> meinStruct * getMeinArray(void)
> {
>     return meinArray;
> }

Hier stimmen die Typen auch nicht. Der Compiler sollte hier einen 
Typkonflikt anmahnen.

> void setMeinArray(void)
> {
>     uint32 neuerWert = 200;
>     meinStruct * array = getMeinArray();
>     array[1][1].uint32_variable = neuerWert;

Das wird zu einem Fehler führen, da array[1] bereits vom Typ meinStruct 
ist und nicht mehr dereferenziert werden kann, was du aber mit dem 
zweiten [1] versuchst. Ursprung dieses Problems ist der falsche 
Rückgabetyp von getMeinArray().

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
guest schrieb:
> Dazu kommt noch:
> array[x] == *(array+x)

Und, damit die wirklich schönen Ecken der Sprache C nicht völlig in 
Vergessenheit geraten:

array[x] == x[array]

Oliver

: Bearbeitet durch User
von guest (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jaja, Ihr habt ja Recht :(
Das geht so nur mit eindimensionalen Arrays.

So wäre es wohl richtiger:
meinStruct( *getMeinArray( void ) )[DIM_1][DIM_2]
{
    return &meinArray;
}
void setMeinArray( void )
{
    uint32_t neuerWert = 200;
    meinStruct( *array )[DIM_1][DIM_2] = getMeinArray();
    array[1][1]->uint32_variable = neuerWert;
    array[0][1]->sint32variable = 400;
    array[1][0]->myEnum = MEIN_ELEMENT_2;
    getMeinArray()[0][0]->uint32_variable = 99;
}

Und da bietet sich dann wirklich ein passender typedef an:
#include <stdint.h>

#define DIM_1   2
#define DIM_2   2

typedef enum
{
    MEIN_ELEMENT_1 = 1,
    MEIN_ELEMENT_2 = 2
} meinEnum;

typedef struct
{
    uint32_t uint32_variable;
    int32_t sint32variable;
    meinEnum myEnum;
} meinStruct, MeinStructArray[DIM_1][DIM_2];

MeinStructArray meinArray = {
    {
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_1 },
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_2 }
    },
    {
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_1 },
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_2 }
    }
};

MeinStructArray* getMeinArray( void )
{
    return &meinArray;
}

void setMeinArray( void )
{
    uint32_t neuerWert = 200;
    MeinStructArray* array = getMeinArray();
    array[1][1]->uint32_variable = neuerWert;
    // ...
}

int main()
{
    setMeinArray();
}

von guest (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mist, das ist natürlich immer noch verkehrt :(
void setMeinArray( void )
{
    uint32_t neuerWert = 200;
    MeinStructArray* array = getMeinArray();
    (*array)[1][1].uint32_variable = neuerWert;
    (*array)[0][1].sint32variable = 400;
    (*array)[1][0].myEnum = MEIN_ELEMENT_2;
    (*getMeinArray())[0][0].uint32_variable = 99;
}

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Das ist dann die Lösung, die ich schon in 
Beitrag "Re: 2D Array als Struct definiert und mittels Zeiger darauf zugreifen" vorgeschlagen 
hatte.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.