[Anfänger]: zweidimisionales Array an Funktion Übergeben.



    • 0b0001 ist kein Standard sondern nur eine Compilererweiterung
    • Serial.println(feld[1][zweite_Zeile]); du verwechselst Zeilen mit Spalten
      - wenn du mit wirklichen Arrays von Arrays arbeitest, hast du auch die Möglichkeit, den Compiler für dich Typprüfungen machen zu lassen; da musst du aber selbst explizit tätig werden:
    void fkt(int x,int y,int a[3][4]) {printf("%d",a[0][0]);}
    
    int main()
    {
      int a[3][4];
      fkt(3,4,a); /* OK */
      ...
    }
    
    int main()
    {
      int a[1][4]; /* Typ ändert sich... */
      fkt(3,4,a);  /* ...Compiler gibt aber keine Warnung */
      ...
    }
    

    deshalb setzt man hier Zeiger auf (Doppel)Arrays ein, und der Compiler warnt dann:

    void fkt(int x,int y,int a[][3][4]) {printf("%d",(*a)[0][0]);}
    
    int main()
    {
      int a[1][4]; /* Typ ändert sich... */
      fkt(3,4,&a);  /* ...Compiler gibt Warnung aus */
      ...
    }
    

    Du kannst davon ausgehen, dass in der Praxis solche Diskrepanzen nicht so übersichtlich dicht beieinander stehen wie hier im Beispiel sondern über viele Zeilen und Module verstreut, der Compiler hier also gute Dienste leisten kann, denn dem sind verstreut liegende Diskrepanzen egal.



  • Wenn man ein 2D-Array "am Stück" braucht, oder aus anderen Gründen mit "Array aus Arrays" hadert, kann man auch ein einfaches Array nehmen

    int *array = malloc (breite*hoehe*sizeof(int));
    

    und dann so darauf zugreifen

    int get (unsigned x, unsigned y)
    {
       return array[x%breite+y*breite];
    }
    


  • Das mit dem Zeiger habe ich jetzt so einigermaßen verstanden. Ich habe mir noch mal
    ein einfacheres Beispiel ausgedacht um mein Anliegen noch verständlicher zu machen.

    Ich verstehe nämlich leider das Beispiel von SeppJ nicht:

    void foo_2D(int size_x, int (*array)[456]);
    
    int main()
    {
      int mein_2D_array[123][456];
      foo_2D(123, mein_array);
    }
    

    Was bedeutet foo ? Wieso dieser Zeiger *array ?

    void foo_2D(int size_x, int size_y, int *array)
    {
      int element_an_34_56 = *(array + 34*size_y + 56);  // mein_array[34][56]
    }
    
    int main()
    {
      int mein_2D_array[123][456];
      foo_2D(123, 456, &mein_array[0][0]);
    }
    

    In Zeile3 hast du mein_array[34][56] und in Zeile8 mein_2D-array[123][456].
    Jetzt bin ich total verwirrt.
    Kannst du mir bitte das Gezeigte noch mal mit meinem Beispiel erklären ?
    Ist wirklich schwierig wenn zwei Menschen unterschiedliche Denkweisen haben.
    Bitte nicht Böse sein.

    /*2D-Arrays und Zeiger*/
    
    /* INTERN werden mehrdimensionale Arrays(mit fest vorgegebenen Elementen */
    /* und bekannter Größe) eindimensional angelegt. */
    
    /* Wenn also z. B. ein Array deklariert ist mit int mein_ertses_Array[3][5] */
    
    /* dann sind die Aufrufe: mein_Array[Zeile][Spalte]  */
    
    /*                        mein_Array[0][Zeile * Breite + Spalte] gleichwertig.*/
    
    void main()
    {
    
    int mein_erstes_Array[3][5] = {      /*Spalte 0*/    /*Spalte 1*/   /*Spalte 2*/   /*Spalte 3*/    /*Spalte 4*/
                                     {
                                             7,               11,            13,            17,             19,     /*Zeile 0*/
                                     },
    
                                     {
                                             23,              29,            59,            61,             67,     /*Zeile 1*/
                                     },
    
                                     {
                                             71,              73,            79,            83,              89,     /*Zeile 2*/
                                     }
                                  };
    
    int mein_zweites_Array[3][7] = {        /*Spalte 0*/    /*Spalte 1*/   /*Spalte 2*/   /*Spalte 3*/   /*Spalte 4*/   /*Spalte 5*/   /*Spalte 6*/
                                      {
                                                 2,              4,             6,             8,             10,            12,            14      /*Zeile 0*/
                                      },
    
                                      {
                                                12,             14,            16,            18,             110,          112,            114     /*Zeile 1*/
                                      },
    
                                      {
                                                22,             24,            26,            28,             210,          212,            214     /*Zeile 2*/
                                      }
                                   };
    
    int gesamtanzahl_Elemente_a1 = sizeof(mein_erstes_Array) / sizeof(int);
    printf ("Gesamtanzahl der A1-Elemente: %d\n", gesamtanzahl_Elemente_a1);
    
    int *zeiger = &mein_erstes_Array[0][0]; /*Position des Zeigers auf das erstes Element des Array setzen. */
    
    for(int i = 0 ; i < gesamtanzahl_Elemente_a1 ; i++)
        {
    printf ("Primzahlen aus mein_erstes_Array: %d\n", *zeiger );
    zeiger++;
        }
    
    printf("\n\n");
    
    int gesamtanzahl_Elemente_a2 = sizeof(mein_zweites_Array) / sizeof(int);
    printf ("Gesamtanzahl der A2-Elemente: %d\n", gesamtanzahl_Elemente_a2);
    
    int *zeiger2 = &mein_zweites_Array[0][0]; /*Position des Zeigers auf das erstes Element des Array setzen. */
    
    for(int i = 0 ; i < gesamtanzahl_Elemente_a2 ; i++)
        {
    printf ("Zahlen aus mein_zweites_Array: %d\n", *zeiger2 );
    zeiger2++;
        }
    }
    

    AUSGABE:

    Gesamtanzahl der A1-Elemente: 15
    Primzahlen aus mein_erstes_Array: 7
    Primzahlen aus mein_erstes_Array: 11
    Primzahlen aus mein_erstes_Array: 13
    Primzahlen aus mein_erstes_Array: 17
    Primzahlen aus mein_erstes_Array: 19
    Primzahlen aus mein_erstes_Array: 23
    Primzahlen aus mein_erstes_Array: 29
    Primzahlen aus mein_erstes_Array: 59
    Primzahlen aus mein_erstes_Array: 61
    Primzahlen aus mein_erstes_Array: 67
    Primzahlen aus mein_erstes_Array: 71
    Primzahlen aus mein_erstes_Array: 73
    Primzahlen aus mein_erstes_Array: 79
    Primzahlen aus mein_erstes_Array: 83
    Primzahlen aus mein_erstes_Array: 89

    Gesamtanzahl der A2-Elemente: 21
    Zahlen aus mein_zweites_Array: 2
    Zahlen aus mein_zweites_Array: 4
    Zahlen aus mein_zweites_Array: 6
    Zahlen aus mein_zweites_Array: 8
    Zahlen aus mein_zweites_Array: 10
    Zahlen aus mein_zweites_Array: 12
    Zahlen aus mein_zweites_Array: 14
    Zahlen aus mein_zweites_Array: 12
    Zahlen aus mein_zweites_Array: 14
    Zahlen aus mein_zweites_Array: 16
    Zahlen aus mein_zweites_Array: 18
    Zahlen aus mein_zweites_Array: 110
    Zahlen aus mein_zweites_Array: 112
    Zahlen aus mein_zweites_Array: 114
    Zahlen aus mein_zweites_Array: 22
    Zahlen aus mein_zweites_Array: 24
    Zahlen aus mein_zweites_Array: 26
    Zahlen aus mein_zweites_Array: 28
    Zahlen aus mein_zweites_Array: 210
    Zahlen aus mein_zweites_Array: 212
    Zahlen aus mein_zweites_Array: 214

    Process returned 21 (0x15) execution time : 0.232 s
    Press any key to continue.


  • Mod

    Ardo-Uno schrieb:

    Was bedeutet foo ?

    Das ist ein Platzhaltername.
    https://de.wikipedia.org/wiki/Fubar#Foo_im_IT-Umfeld

    Wieso dieser Zeiger *array ?

    Vorsicht: Du musst den ganzen Ausdruck betrachten. Da steht int (*array)[456] . Das ist eine Variable namens Array vom Typ Zeiger auf Array[456] von int. Ich demonstriere hier, dass man ein Array von Arrays auf die gleiche Weise an eine Funktion übergeben kann, wie ein Array von irgendwas anderes. Wenn man ein z.B. Array von double hätte, könnte man dieses schließlich über einen Zeiger auf double an eine Funktion übergeben. Und bei Arrays von Arrays entsprechend über einen Zeiger auf ein Array.

    Wie schon erläutert, ist dieser Ansatz aber selten praktikabel, weil man die Größe des inneren Arrays (im Beispiel 456) im Voraus kennen muss, was meistens nicht der Fall ist.

    In Zeile3 hast du mein_array[34][56] und in Zeile8 mein_2D-array[123][456].

    Das letztere ist die Definition des Arrays, das erstere soll als Erläuterung dienen, was der Beispielcode macht. Er greift auf das 56. Element der 34. Zeile des Arrays von Arrays zu.

    [...dein restlicher Beitrag...]

    Hast du eine Frage dazu?

    PS: Googel mal nach "Plenken"!



  • Sooo - Jetzt klappt es so wie ich es mir vorgestellt habe. Noch mal vielen Dank für die Tipps.
    PS: Die Plenken-Sünden habe ich auch beseitigt 🙂

    #include <stdio.h>
    #include <stdlib.h>
    
    int mein_erstes_Array[3][5] = {                                     
    						 {
                                             		   7,  11, 13, 17, 19,    
                                    			  },
    
                                     			  {
                                            		    23, 29, 59, 61, 67,                  
    						  },
    
                                    			 {
                                             		   71, 73, 79, 83,  89,  
                                     			  }
                                  		     };
    
    int mein_zweites_Array[3][7] = {        
                                      			   {
                                                 		     2, 4, 6, 8, 10, 12, 14
                                      			   },
    
                                      			   {
                                                		     12, 14, 16, 18, 110, 112, 114
                                      			    },
    
                                     			    {
                                                		      22, 24, 26,  28, 210, 212, 214
                                     			     }
                                  		         	};
    
    int zeige_Grafik(int zeile, int spalte, int unbek_array[zeile][spalte])
    {
    printf("\n\n");
    //int gesamtanzahl_Elemente = sizeof(unbek_array) / sizeof(int);
    int gesamtanzahl_Elemente = zeile * spalte;
    printf ("Gesamtanzahl der Elemente: %d\n", gesamtanzahl_Elemente);
    
    int *zeiger = &unbek_array[0][0]; /*Position des Zeigers auf das erstes Element des Array setzen. */
    
    for(int i = 0 ; i < gesamtanzahl_Elemente ; i++)
        {
    printf ("Zahlen aus dem Array: %d\n", *zeiger );
    zeiger++;
        }
    }
    
    int zeige_Grafik2(int zeile, int spalte, int unbek_array[zeile][spalte])
    {
    printf("\n\n");
    int gesamtanzahl_Elemente = zeile * spalte;
    int zeilenzaehler0 = 0;
    int zeilenzaehler1 = 0;
    int zeilenzaehler2 = 0;
    
    for(int i = 0 ; i < gesamtanzahl_Elemente / 3 ; i++)
        {
    printf("\n\n");
    printf("Zahlen aus dem Array: %d\n", unbek_array[0][zeilenzaehler0]);
    printf("Zahlen aus dem Array: %d\n", unbek_array[1][zeilenzaehler1]);
    printf("Zahlen aus dem Array: %d\n", unbek_array[2][zeilenzaehler2]);
    zeilenzaehler0++;
    zeilenzaehler1++;
    zeilenzaehler2++;
        }
    }
    
    void main()
    {
    zeige_Grafik(3,7,mein_zweites_Array);
    printf("\n\n");
    zeige_Grafik2(3,5,mein_erstes_Array);
    }
    

    AUSGABE am Terminal:

    Gesamtanzahl der Elemente: 21
    Zahlen aus dem Array: 2
    Zahlen aus dem Array: 4
    Zahlen aus dem Array: 6
    Zahlen aus dem Array: 8
    Zahlen aus dem Array: 10
    Zahlen aus dem Array: 12
    Zahlen aus dem Array: 14
    Zahlen aus dem Array: 12
    Zahlen aus dem Array: 14
    Zahlen aus dem Array: 16
    Zahlen aus dem Array: 18
    Zahlen aus dem Array: 110
    Zahlen aus dem Array: 112
    Zahlen aus dem Array: 114
    Zahlen aus dem Array: 22
    Zahlen aus dem Array: 24
    Zahlen aus dem Array: 26
    Zahlen aus dem Array: 28
    Zahlen aus dem Array: 210
    Zahlen aus dem Array: 212
    Zahlen aus dem Array: 214

    Zahlen aus dem Array: 7
    Zahlen aus dem Array: 23
    Zahlen aus dem Array: 71

    Zahlen aus dem Array: 11
    Zahlen aus dem Array: 29
    Zahlen aus dem Array: 73

    Zahlen aus dem Array: 13
    Zahlen aus dem Array: 59
    Zahlen aus dem Array: 79

    Zahlen aus dem Array: 17
    Zahlen aus dem Array: 61
    Zahlen aus dem Array: 83

    Zahlen aus dem Array: 19
    Zahlen aus dem Array: 67
    Zahlen aus dem Array: 89



  • Uuups, jetzt sind mir die Arrays doch verutscht, obwohl ich die Leerzeichen entfernt hatte 😞



  • Eine Frage hätte ich dann doch noch: Bei

    funktion_2d(3,5,&mein_Array[0][0]);
    

    Übergibst du der Funktion funktion_2d die Anfangsadresse des Arrays als Parameter.
    In der Funktionsdeklaration gibst du aber nicht an wohin der Zeiger zeigen soll sondern erst später bei der Parameterübergabe.

    Ich habe außerdem ausprobiert ob es auch OHNE &-Zeichen geht. Und siehe da es liefert ebenfalls das richtige Ergebnis 61.

    funktion_2d(3,5,mein_Array);
    

    Wie ist das Möglich ? Der Zeiger zeigt ja dann IRGENDWO hin, was man ja nicht machen soll.
    Hier noch mal SeppJ Vorschlag:

    #include <stdio.h>
    #include <stdlib.h>
    
    int mein_Array[3][5] = {
                                {
                                  7, 11, 13, 17, 19,
                                },
    
                                {
                                  23, 29, 59, 61, 67,
                                },
    
                                {
                                  71, 73, 79, 83, 89,
                                }
                            };
    
    void funktion_2d(int zeile, int spalte, int *unbek_array)
    {
    int element_an_1_3 = *(unbek_array + 1 * spalte + 3);
    
    printf("\n\n");
    printf("element in Zeile-1 und Spalte-3: %d\n", element_an_1_3); // gibt die Zahl 61 aus.
    }
    
    void main()
    {
    funktion_2d(3,5,&mein_Array[0][0]);
    }
    


  • &mein_Array[0][0] liefert eine Adresse von einem int . Hier vom ersten Element vom Array

    meinArray liefert eine Adresse von einem int[3][5] . Das ist die Anfangsadresse von dem Array.

    Beide Adressen sind hier identisch, jedoch nicht die Typen. Dies wird jedoch beim Funktionsaufruf verdeckt, so dass die Funktion weiterhin funktioniert.



  • Habe ich richtig verstanden ?
    Dieser Ausdruck liefert den Anfang des Arrays

    &mein_Array[0][0]);
    

    Und dieser Ausdruck liefert mir ebenfalls den Anfang des Arrays.
    Der Name eines Arrays OHNE Indexangaben und OHNE Adressoperator
    gibt immer die Startadresse des Arrays zurück?

    mein_Array
    


  • Ardo-Uno schrieb:

    Habe ich richtig verstanden ?
    Dieser Ausdruck liefert den Anfang des Arrays

    &mein_Array[0][0]);
    

    Und dieser Ausdruck liefert mir ebenfalls den Anfang des Arrays.
    Der Name eines Arrays OHNE Indexangaben und OHNE Adressoperator
    gibt immer die Startadresse des Arrays zurück?

    mein_Array
    

    Zu deiner Verwirrung: Es geht sogar sowas:

    &mein_Array
    

    Aber frag mich nicht warum.
    Adresse von Adresse?
    Ist wohl ein Bug in der C-Grammar-Definition, der nie jemanden gestört hat.



  • Klappe halten wenn man keine Ahnung hat heißt es da.
    Die C-Altvorderen eines Bugs zu verdächtigen kann nur einem Dorftrottel ohne Ahnung aber mit übersteigertem Mitteilungsbedürfnis passieren.



  • Fricky667 schrieb:

    Zu deiner Verwirrung: Es geht sogar sowas:

    &mein_Array
    

    Aber frag mich nicht warum.
    Adresse von Adresse?
    Ist wohl ein Bug in der C-Grammar-Definition, der nie jemanden gestört hat.

    &mein_Array ist ein Zeiger, der auf das Array zeigt:

    int mein_array[5];
    
    • &mein_array ist ein int(*mein_array)[4] . Ein Zeiger auf das Array als Ganzes.
    • mein_array zerfällt in Ausdrücken zu einem Zeiger auf das erste Element des Array: int* .
    • &mein_array[0] ergibt explizit einen Zeiger auf das erste Element.

    Edit: Mist, der C-Guru hat bereits zugeschlagen.



  • Wutz schrieb:

    Klappe halten wenn man keine Ahnung hat heißt es da.
    Die C-Altvorderen eines Bugs zu verdächtigen kann nur einem Dorftrottel ohne Ahnung aber mit übersteigertem Mitteilungsbedürfnis passieren.

    Ach, mein lieber Proll-Troll ist wieder da. 😃
    Willst du, dass gleich der nächste Thread wegen deiner Scheiße zugemacht wird?



  • Techel schrieb:

    &mein_array ist ein int(mein_array)[4]
    mein_array zerfällt in Ausdrücken zu einem Zeiger auf das erste Element des Array: int
    .

    Gibt es denn eine Situation in der man '&mein_array' nehmen muss und nicht einfach 'mein_array' hinschreiben kann?



  • Ah, folgendes ...

    void test (int(*array)[4]){}
    
    int main()
    {
        int array[4];
        test (&array); // geht
        test (array);  // fehler
    }
    

    Alles klar. Thx Techel!



  • Was soll das gegenseitige angezicke ? Ich dachte das hier wäre ein professionelles Forum und kein Kindergarten a la: "Ich aber kann es besser".

    Noch mal zu meiner Frage die ich aber in der Zwischenzeit im Internet als gelöst gefunden habe.

    Zitat:
    Zeiger und Arrays haben vieles gemeinsam. Tatsächlich setzten die meisten C-Compiler alle Array-Befehle in Zeiger-Befehle um. der Name eines Arrays (also der Variablename) ohne Indexangabe und Adressoperator gibt die Startadresse des Arrays zurück, d.h. die Adresse des ersten Elements.

    Somit ist:

    pointer = &array[0];
    

    gleichwertig mit:

    pointer = array;
    

    Zitat ende.

    test (array);  // KEIN Fehler !!!


  • Mod

    Ein Array ist kein Zeiger, ein Zeiger ist kein Array! Sei unbedingt vorsichtig mit zufälligen Aussagen aus dem Internet, viele Leute haben von C weit weniger Ahnung als sie denken und verbreiten dann gefährliches Halbwissen. Siehe z.B. Fricky667 in diesem Thread. Hier wurden seine Aussagen richtig gestellt. Wenn du anderswo gleichartige Aussagen ohne Korrektur findest, dann bloß, weil es niemand korrigiert hat.

    DirkB hat bereits genau erklärt, worauf es hier ankommt:

    DirkB schrieb:

    &mein_Array[0][0] liefert eine Adresse von einem int . Hier vom ersten Element vom Array

    meinArray liefert eine Adresse von einem int[3][5] . Das ist die Anfangsadresse von dem Array.

    Beide Adressen sind hier identisch, jedoch nicht die Typen. Dies wird jedoch beim Funktionsaufruf verdeckt, so dass die Funktion weiterhin funktioniert.



  • Das war eine gute Diskussion zwischen Techel und mir. Bleib mal locker. 🙂


  • Mod

    Mein Eindruck ist, dass ein großer Teil der Verwirrung im Zusammenhang mit Array und Zeigern von einem fehlenden Verständnis für die verschiedenen Wertkategorien (l- und rvalues) und ungenauer Verwendung von Begriffen, die nicht deutlich machen, welche Kategorie gemeint ist.
    Gerade beim Thema Zeiger ist es einerseits wichtig, anderseits oft unklar, was gemeint ist:
    1. ein Zeigerwert, d.h. ein bestimmtes Bitmuster, dass eine bestimmte Speicherstelle bezeichnet (und hier ist unglücklich, dass wir vom Englischen kommend, von l- und r-Werten reden), oder
    2. ein Zeigerobjekt, also eine Speicherstelle, die einen Zeigerwert (s.o.) speichern kann

    Zeigerwert       | Zeigerobjekt
    verweist auf ein Objekt                         ja               | nein
    änderbar                                        nein             | ja (wenn nicht const qualifiziert)
    ist ein Speicherort                             nein             | ja
    hat eine Adresse                                nein             | ja
    ein Zeigerwert existiert, der darauf zeigt      nein             | ja
    

    Das sind also völlig verschiedene Dinge. Und doch werden beide oft einfach nur Zeiger genannt, vielleicht noch mit wechselnden Bedeutungen innerhalb desselben Satzes/Gedankens. Mit ein bisschen Arraysauce dazu ist es dann kein Wunder, dass Verwirrung resultiert.

    Als Sahnehäubchen obendrauf noch die etwas unsinnige Herangehensweise des C-Standards, die besagt, dass ein lvalue generell in ein entsprechendes (und hier gibt es wesentliche Unterschiede zwischen Arrays und nicht-Arrays) rvalue gewandelt wird, sofern es nicht Operand eines Operators ist, der eben diese Umwandlung unterdrückt. Der Weg von C++ macht mehr Sinn: Ausdrücke stehen zunächst mal nur für sich selbst, falls eine Umwandlung erfordelich ist, wird die erst durch den jeweiligen Operator induziert. Immerhin hat die Art der Interpretation keinerlei Einfluss auf das Verhalten eines Programmes, das sowohl gültiges C als auch C++ ist (außer bei leerem volatile-read).



  • camper schrieb:

    Mein Eindruck ist, dass ein großer Teil der Verwirrung im Zusammenhang mit Array und Zeigern von einem fehlenden Verständnis für die verschiedenen Wertkategorien (l- und rvalues) und ungenauer Verwendung von Begriffen, die nicht deutlich machen, welche Kategorie gemeint ist.
    Gerade beim Thema Zeiger ist es einerseits wichtig, anderseits oft unklar, was gemeint ist:
    1. ein Zeigerwert, d.h. ein bestimmtes Bitmuster, dass eine bestimmte Speicherstelle bezeichnet (und hier ist unglücklich, dass wir vom Englischen kommend, von l- und r-Werten reden), oder
    2. ein Zeigerobjekt, also eine Speicherstelle, die einen Zeigerwert (s.o.) speichern kann

    Manche reden ja von Zeiger und Zeigervariable, wenn sie das unterscheiden wollen. Ersteres ist bei dir der Zeigerwert und letzteres dein Zeigerobjekt.

    Aber im sonst üblichen flapsigen Sprachgebrauch kann "Zeiger" eben beides sein. Da wird das erst durch den Kontext klar, was gemeint ist.

    Was ich aber so richtig doof finde, ist die Formulierung: "irgendwas *zerfällt* in einen Zeiger". Wer hat sich das bloß ausgedacht. 😞


Anmelden zum Antworten