Forum: Compiler & IDEs Pointer und mehrdimensionale Arrays


von LtData (Gast)


Lesenswert?

Hi!

Ich habe mal eine Frage zu Pointern. Und zwar wie spreche ich damit 
mehrdimensionale arrays an?
Wenn ich zum Pointer auf ein normales Array z.B. 1 dazuaddiere, dann 
komm ich ja aufs selbe raus, als wenn ich array[1] geschrieben hätte. 
Aber was passiert wie gesagt bei beispielsweise 2 dimensionalen Arrays.

von Oliver (Gast)


Lesenswert?

Ho!

Beispiel:

void test(int m[3][3])
{
 m[1][0] = 10;
}

void main(void)
{
 int a[3][3]; //Drei Zeilen, drei Spalten
 test(a);
}

Versuch das mal.

von Axel Beierlein (Gast)


Lesenswert?

Da gibt es einen ganz tollen Effekt, der das Arbeiten mit Pointern und 
mehrdimensionalen array´s erheblich vereinfacht. Und zwar speichert der 
Computer normale als auch mehrdim. A. im Speicher hintereinander ab und 
zwar wenn Du ein 3x4 Array hast, dann kommt die erste Zeile mit 4 
Werten, gleich danach die zweite mit 4 Werten danach die dritte. Du 
läufst also mit dem Pointer durch den Speicherbereich.
Lässt sich daher auch alles mit ner kleinen Schleife erledigen.

Achte aber bitte drauf, dass dein Pointer den gleichen Typ hat wie dein 
Array sonst kommt Müll raus (ist leider ein oft gemachter Fehler der mir 
auch ab und an passiert).

Gruß Axel

von Axel Beierlein (Gast)


Lesenswert?

@Oliver

was hat denn Dein Sourcecode mit Pointern zu tun ?

;-)

gruß Axel

von Joerg Wunsch (Gast)


Lesenswert?

Daß die Funktion test() einen solchen übergeben bekommt, auch
wenn das auf den ersten Blick gar nicht so aussieht. ;-)

von Axel Beierlein (Gast)


Lesenswert?

ist aber zum Erklären ein schreckliches Beispiel. Solche Codes helfen 
keinem die Problematik mit Pointern zu verstehen!

Ausserdem bekommt die Funktion eine Adresse übergeben und keinen 
Pointer!

Also nicht ganz richtig.

Ein Pointer hat als Inhalt eine Adresse (er wird ja auch anders 
deklariert z.B. int *ptr;) und der Vektor
m[0][0] ist in Wahrheit die Anfangsadresse des zweidimensionalen Vektors 
die einem Pointer mittels
ptr = m[0][0]; übergeben wird.

Aber kein Pointer! Sonst müsste ich ja den Inhalt von m auch mit dem 
Dereferezierungsoperator * ansprechen können.

Ich bin leider so wehement, weil ich aus diesem Grunde früher die Dinge 
mit dem Pointer und den Arrays auch nicht verstanden habe. Dass es eine 
enge Bindung zwischen Pointern und Array´s gibt ist richtig, man darf 
Sie aber nicht gleichsetzen sonst versteht man die Materie leider gar 
nicht.
Hat man das Pointerproblem gelöst, dann kommt man automatisch auf die

von Axel Beierlein (Gast)


Lesenswert?

Bindung zwischen Pointer und Array´s.

.............hatte ich ganz vergessen und das

;-)
Gruß Axel

auch noch.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Axel, ich glaube nicht dass Jörg Nachhilfe in Sachen Zeiger braucht ;-)

Irgendwas haust du da durcheinander.

"m[0][0] ist in Wahrheit die Anfangsadresse des zweidimensionalen 
Vektors"

m[0][0] ist sicher keine Adresse sondern der erste Wert im Array.

m bzw. a lässt sich prima mit dem Dereferenzierungsoperator verwenden, 
allerdings musst du ihn 2 Mal angeben, da du beim ersten Mal nur einen 
Zeiger auf das "Unterarray" bekommst.

von Joerg Wunsch (Gast)


Lesenswert?

Du irrst dennoch.  Die Funktion bekommt in der Tat nur einen
Pointer übergeben.  Für einen Funktionsparameter, der auf ein
Array zeigt, gibt es immer auch eine alternative, vollständig
kompatible Schreibweise, ihn als Zeiger auszudrücken.  Daher
ist es auch völlig äquivalent, ob man

int main(int argc, char **argv)

oder

int main(int argc, char *argv[])

schreibt.

Aber ich gebe Dir natürlich völlig recht, daß das von Oliver
gewählte Beispiel eher ungünstig zur Verdeutlichung der
Problematik ist.

von Oliver (Gast)


Lesenswert?

@all!

Ich habe das Gefühl, alle anwesenden haben noch nie Pointer auf 
mehrdimensionale Arrays einer Funktion übergeben. Ich sehe hier keinen 
weiteren Lösungsvorschlag für unseren Androiden.

Steht die Dimension und Größe fest, kann sie direkt in der 
Funktionsdefinition festgeschrieben werden. Will man der Funktion 
mehrdimensionale Arrays übergeben, dessen Größe variabel sein sollen, so 
sieht das allgemein für ein dreidimensionales Array so aus:

void test(int*** m, int dim1, int dim2, int dim3)
{
for (int i = 0; i<dim1;i++)
for (int j = 0; j<dim2;j++)
for (int k = 0; k<dim3;k++)
{
 // Zugriff durch
((int*)m)[i * dim1 *dim2 *dim3 +j *dim3 +k]
}

}

Ist das vielleicht ein besseres Beispiel ;-)

Grüße
Oliver

von Axel Beierlein (Gast)


Lesenswert?

@Andreas

korrekt, Deine Aussage. m stellt hier aber die Anfangsadresse dar:
m und &m[0][0] sind hier gleichwertig.

Da habe ich mich vertan sorry. Ich sage ja auch ich mache Fehler.

@Oliver

Erkläre LtData doch was Du meinst. Oder hast Du C anhand von purem 
Sourcecode gelernt. Ausserdem fehlt mir bei deinem etwas Kommentar.
Und ein besseres Beispiel zur Erklärung der Frage ist dein letztes 
definitv nicht.

von Axel Beierlein (Gast)


Lesenswert?

@LtData
Mal ein Sourcecode von mir zum Thema Pointer und array´s
_____________________________________________

#include <stdio.h>

#define ROWS 3  /* Zeilenzahl */
#define COLS 4  /* Spaltenzahl */

void main(void)
{
    /* 2D Array mit Initialisierung, 2D Array wird
       zeilenweise ohne Luecken abgespeichert:
       m[0][0] m[0][1] ... m[0][3] m[1][0] m[1][1]...m[1][3]...m[2][3]
       |----- Zeile 0 ------------|------- Zeile 1 ---------|-- .....
       Dadurch kann man sich die 3*4 Matrix in einem 1D Array mit
       3*4=12 Elementen gespeichert vorstellen vorstellen:
       Index der Matrix |Index des aequivalienten Vektors
            i j         |    k=i*COLS+j
       -----------------|--------------------------------
            0 0         |    0
            0 1         |    1
            0 2         |    2
            0 3         |    3
            1 0         |    4
            1 1         |    5
            1 2         |    6
            ...         |   ...
            2 2         |   10
            2 3         |   11
    */
    float m[ROWS][COLS] = {0.1, 0.2, 0.3, 0.4,
                           0.5, 0.6, 0.7, 0.8,
                           0.9, 1.0, 1.1, 1.2};
    float *fpt=NULL; /* Pointer auf float, geerdet */
    int i,j;

    printf("Zugriff ueber Pointer, der das 2D Feld durchwandert\n");
    fpt=&m[0][0];                /* Pointer auf Element 0,0 setzen   */
    for(i=0; i<ROWS*COLS; i++)   /* alle Feldelemente ...            */
    {  printf("%4.1f ", *fpt++); /* Wert ausgeben und danach Pointer */
    }                            /* ein Element weiter setzen        */

    printf("\n\nZugriff mit Pointer und zwei Indizes\n");
    fpt=&m[0][0];              /* Pointer auf das Element 0,0 setzen */
    for(i=0; i<ROWS; i++)      /* Zeilen...    */
    {  for(j=0; j<COLS; j++)   /* Spalten ...  */
       {  printf("%4.1f ",*(fpt+i*COLS+j));
       }
       putchar('\n'); /* neue Zeile */
    }

    printf("\nZugriff ueber Feldname und 2 Indizes\n");
    for(i=0; i<ROWS; i++)      /* Zeilen...    */
    {  for(j=0; j<COLS; j++)   /* Spalten ...  */
       {  printf("%4.1f ",m[i][j]);
       }
       putchar('\n'); /* neue Zeile */
    }
}

von LtData (Gast)


Lesenswert?

Hallo!

Erstmal vielen Dank an euch alle! Eigentlich hätte ich nur die erste 
Antwort von Axel gebraucht (ich hatte mir nämlich schon überlegt, daß 
die Daten ja schliesslich im Speicher irgendwie hintereinander kommen 
müssen, konnte aber nicht rausfinden ob nun zeilen- oder spaltenweise), 
aber insbesondere Olivers letztes Posting hat doch ganz erheblich zum 
Verständnis der Zusammenhänge zwischen Pointern und Arrays beigetragen 
(auch wenn ich mir das erstmal genau ansehen musste, um das auch zu 
verstehen ;-)).
Ich denke mal, auf die Verwendungsmöglichkeiten wäre ich sonst nicht 
gekommen. In meinem C++ Buch steht nämlich leider nix über Pointer auf 
mehrdimensionale Arrays drinnen.

Nochmals Vielen Dank für die nette Hilfe!

von Joerg Wunsch (Gast)


Lesenswert?

Nein, das ist sogar ziemlicher Quatsch.  Wofür übergibst Du
einen int ***, wenn Du ihn dann doch nur auf int * casten
willst?  Auch die Multiplikation macht implizite Annahmen über
das Layout des Arrays, die inkorrekt sind.

Hier mal ein witziges Beispiel, das C99-Syntax mit variable-length
arrays benutzt (die der aktuelle gcc aber durchaus kann).

#include <stdio.h>

char
arry[2][3][6] = {
        {
                "Hello",
                "world",
                "foo!"
        },
        {
                "Thats",
                "some",
                "crap!"
        }
};

char
get(int a, int b, int c, char x[a][b][c])
{
        return x[1][2][3];
}

int
main(void)
{
        printf("char = %c\n", get(2, 3, 6, arry));
        return 0;
}

von Oliver (Gast)


Lesenswert?

In einem hast Du Recht

((int*)m)[i * dim1 *dim2 *dim3 +j *dim3 +k]

muß heißen

((int*)m)[i * dim2 *dim3 +j *dim3 +k]

Ansonsten ist nix quatsch.

Der Pointer in der Funktionsdeklaration zeigt auf ein 3D-Array, welches 
ihr einfach als Parameter übergeben werden kann. Dieser wird in einen 
Int-Pointer gecastet, um direkt auf das Element zugreifen zu können. Wer 
sich mal etwas näher mit Compiler und deren Arbeitsweise 
auseinandergesetzt hat, der weiss wie sie es machen. Sie speichern 
Arrays, auch mehrdimensionale, immer linear ab.

von Axel Beierlein (Gast)


Lesenswert?

sagte ich das nicht bereits mit dem linearen Abspeichern?
Habe auch noch keinen mehrdimensionalen Speicher gesehen.

aber nichtsdestotrotz dass Du die Problematik mit den Pointern begriffen 
hast, gibt es sicherlich andere, die mit Pointern noch Probs. haben die 
mit Deinem geposteten Text recht wenig anfangen können.

ausserdem lernte ich dass ***zeiger bäbä sind.

So. Aber LtData hat seine Frage ja beantwortet bekommen wie er 
mitteilte. Und da brauchen wir uns hier doch nicht zu streiten.

Daher: Happy Coding! Und schon mal Danke an alle die mir weitergeholfen 
haben/werden :-)))

von Oliver (Gast)


Lesenswert?

Sorry,

war ein schlechter Tag für mich. Ich gehöre zu den armen Schweinen, die 
sich immer ihre eigenen Fragen beantworten müssen. Kein weiterer 
Softwärkerkollege weit und breit in Sicht. Und das schon seit 
Berufsbeginn 1997.

Entschuldigung
Oliver

von Joerg Wunsch (Gast)


Lesenswert?

Ist doch nicht tragisch.  Habe inzwischen auch nochmal
nachgesehen.  Ein

int foo[3][5][7];

ist bei der Parameterübergabe in eine Funktion kompatibel mit
dem Zeiger

int (*foo)[5][7]

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.