Pointer und mehrdimensionale Arrays

Gast #40402
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.
Gast
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
Gast
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
Admin Persönliche Seite
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.
Gast
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.
Gast
@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
Gast
@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.
Gast
@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 */
    }
}
Gast
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!
Gast
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;
}
Gast
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.
Gast
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 :-)))
Gast
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
Gast
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]

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 23 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.