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


von FastExperte (Gast)


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;
1
#define DIM_1   2
2
#define DIM_2   2
3
4
typdef enum{
5
MEIN_ELEMENT_1 = 1,
6
MEIN_ELEMENT_2 =2
7
}meinEnum;
8
9
10
typedef struct{
11
uint32 uint32_variable,
12
sint32 sint32variable
13
meinEnum myEnum
14
}meinStruct;
15
16
meinStruct meinArray[DIM_1][DIM_2] = {
17
    {
18
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_1 },
19
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_2 }
20
    },
21
    {
22
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_1 },
23
        { .uint32_variable = 100,  .sint32variable =  200,  .myEnum= MEIN_ELEMENT_2 }
24
};
25
26
//ich wollte hier die Adresse des Arrays übergeben
27
meinStruct * getMeinArray(void)
28
{
29
    return &meinArray; //bin mir nicht sicher was der ReturnWert sein soll
30
}
31
32
void setMeinArray (void)
33
{
34
35
 uint32 neuerWert = 200;
36
 meinStruct (*ptrMeinStruct)[DIM_2] = getMeinArray();
37
 
38
 //hier habe ich keinen Plant wie ich einzelne Strukturelemente des Arrays
39
 //ansprechen kann und diese überschreiben könnte, mein miserabler Ansatz    //unten
40
 ptrMeinStruct->[1][1].trigs = neuerWert;
41
42
}

von Oliver S. (oliverso)


Lesenswert?

Mit einem typedef gehts einfacher:
1
#include <assert.h>
2
#include <stdint.h>
3
4
#define DIM_1   2
5
#define DIM_2   2
6
7
typedef enum
8
{
9
   MEIN_ELEMENT_1 = 1,
10
   MEIN_ELEMENT_2 = 2
11
} meinEnum;
12
13
typedef struct
14
{
15
   uint32_t uint32_variable;
16
   int32_t sint32variable;
17
   meinEnum myEnum;
18
} meinStruct;
19
20
typedef meinStruct array_of_DIM_2_t[DIM_2];
21
meinStruct meinArray[DIM_1][DIM_2];
22
23
array_of_DIM_2_t * getMeinArray(void)
24
{
25
   return meinArray;
26
}
27
28
int main(void)
29
{
30
31
   array_of_DIM_2_t *ptrMeinStruct = getMeinArray();
32
33
   ptrMeinStruct[1][1].uint32_variable = 200;
34
   ptrMeinStruct[0][1].uint32_variable = 100;
35
   ptrMeinStruct[1][0].uint32_variable = 300;
36
37
   assert(200 == meinArray[1][1].uint32_variable);
38
   assert(100 == meinArray[0][1].uint32_variable);
39
   assert(300 == meinArray[1][0].uint32_variable);
40
}

Oliver

von zitter_ned_aso (Gast)


Lesenswert?

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

oder mit einfachen Zeigern arbeiten:
1
meinStruct* p=&meinArray[0][0];
2
3
meinStruct* temp=p;
4
for(size_t i=0; i<DIM1*DIM2; i++, temp++)                              
5
   printf("x: %d, y: %d\n", temp->x, temp->y);

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> typedef meinStruct array_of_DIM_2_t[DIM_2];

Oder gleich das ganze array:
1
}
2
typedef meinStruct meinArray_t[DIM1][DIM2];
3
4
meinArray_t meinArray;
5
6
meinArray_t* getMeinArray(void)
7
{
8
    return &meinArray;
9
}

Und Zugriff mit:
1
meinArray_t* pointer = getMeinArray();
2
3
(*pointer)[1][1].uint32_variable = 200;

von FastExperte (Gast)


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)


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:
1
typedef meinStruct array_of_DIM_2_t[DIM_2];
2
3
array_of_DIM_2_t * getMeinArray(void)
4
{
5
   return meinArray;
6
}
meinArray ist hier äquivalent zu &meinArray[0] - die Adresse des ersten 
Elements.

Variante 2: Ein Zeiger auf das erste Element des ersten Elements:
1
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:
1
typedef meinStruct meinArray_t[DIM1][DIM2];
2
3
meinArray_t* getMeinArray(void)
4
{
5
    return &meinArray;
6
}
In dem Fall muss der Zeiger dann vor dem Zugriff eben ganz normal 
dereferenziert werden.

von FastExperte (Gast)


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)


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:
1
meinStruct * getMeinArray(void)
2
{
3
    return meinArray;
4
}
5
6
void setMeinArray(void)
7
{
8
    uint32 neuerWert = 200;
9
    meinStruct * array = getMeinArray();
10
    array[1][1].uint32_variable = neuerWert;
11
    array[0][1].sint32variable = 400;
12
    array[1][0].myEnum = MEIN_ELEMENT_2;
13
    getMeinArray()[0][0].uint32_variable = 99;
14
}

von guest (Gast)


Lesenswert?

Noch ne Variante:
1
    (*getMeinArray()).uint32_variable = 88;
2
    // entspricht meinArray[0][0].uint32_variable = 88;

von zitter_ned_aso (Gast)


Lesenswert?

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

Nein, der Datentyp ist bei allen unterschiedlich.

von Rolf M. (rmagnus)


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)


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)


Lesenswert?

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

So wäre es wohl richtiger:
1
meinStruct( *getMeinArray( void ) )[DIM_1][DIM_2]
2
{
3
    return &meinArray;
4
}
5
void setMeinArray( void )
6
{
7
    uint32_t neuerWert = 200;
8
    meinStruct( *array )[DIM_1][DIM_2] = getMeinArray();
9
    array[1][1]->uint32_variable = neuerWert;
10
    array[0][1]->sint32variable = 400;
11
    array[1][0]->myEnum = MEIN_ELEMENT_2;
12
    getMeinArray()[0][0]->uint32_variable = 99;
13
}

Und da bietet sich dann wirklich ein passender typedef an:
1
#include <stdint.h>
2
3
#define DIM_1   2
4
#define DIM_2   2
5
6
typedef enum
7
{
8
    MEIN_ELEMENT_1 = 1,
9
    MEIN_ELEMENT_2 = 2
10
} meinEnum;
11
12
typedef struct
13
{
14
    uint32_t uint32_variable;
15
    int32_t sint32variable;
16
    meinEnum myEnum;
17
} meinStruct, MeinStructArray[DIM_1][DIM_2];
18
19
MeinStructArray meinArray = {
20
    {
21
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_1 },
22
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_2 }
23
    },
24
    {
25
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_1 },
26
        {.uint32_variable = 100,  .sint32variable = 200,  .myEnum = MEIN_ELEMENT_2 }
27
    }
28
};
29
30
MeinStructArray* getMeinArray( void )
31
{
32
    return &meinArray;
33
}
34
35
void setMeinArray( void )
36
{
37
    uint32_t neuerWert = 200;
38
    MeinStructArray* array = getMeinArray();
39
    array[1][1]->uint32_variable = neuerWert;
40
    // ...
41
}
42
43
int main()
44
{
45
    setMeinArray();
46
}

von guest (Gast)


Lesenswert?

Mist, das ist natürlich immer noch verkehrt :(
1
void setMeinArray( void )
2
{
3
    uint32_t neuerWert = 200;
4
    MeinStructArray* array = getMeinArray();
5
    (*array)[1][1].uint32_variable = neuerWert;
6
    (*array)[0][1].sint32variable = 400;
7
    (*array)[1][0].myEnum = MEIN_ELEMENT_2;
8
    (*getMeinArray())[0][0].uint32_variable = 99;
9
}

von Rolf M. (rmagnus)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.