Zweidimensionale Arrays an Funktion übergeben.

klicky

Grünschnabel
Hallo,
ich bin noch absoluter Anfänger in C und versuche schon seit Tagen
die Elemente bzw. Daten eines zweidimensionalen Arrays in einer
Funktion zu Verarbeiten.

Sofern sich das Array INNERHALB der Funktion befindet ist es einfach.
Die Funktion gibt die Daten des Arrays an den Seriellen Monitor aus.
Siehe erstes Programm.

Aber sobald ich die Arrays AUSSERHALB der Funktion (Global) anlege
habe ich Schwierigkeiten Auf die Daten der Zeilen und Spalten zuzu
-greifen.
Ich habe einige Beispiele im Netz gefunden die ich leider nicht
verstanden habe. Sehr unübersichtlich diese Zeiger.

Ich würde den Arrayzugriff gerne wie im zweiten Beispiel realisieren.
Kann mir einer erklären wie das geht ? Mit Beispielcode ?


C:
/*zweidimensionales Array INNERHALB einer Funktion*/

void funktion()
{

int feld[3][15] = {
                       {
                         0xB0,0xB1,0xB2,0xB3,0xB4                         
                       },

                       {
                         7,11,13,17,23
                       },

                       {
                         0b0001,0b0010,0b0011,0b0100,0b0101
                       }                                       
                  };

 
int anzahl_im_array =sizeof(feld) / sizeof(int) / 3 / 3;

int erste_Zeile;
int zweite_Zeile;
int dritte_Zeile;

for(int zaehler = 0 ; zaehler<anzahl_im_array ; zaehler++)
  {

Serial.begin(115200);
//Serial.println(anzahl_im_array);
/*Die Zahlen im Array ausgeben*/
Serial.println(" ");
Serial.println(" ");
Serial.println(feld[0][erste_Zeile],HEX);
Serial.println(feld[1][zweite_Zeile]);
Serial.println(feld[2][dritte_Zeile],BIN);

erste_Zeile++;
zweite_Zeile++;
dritte_Zeile++;
  }
}



void setup()
{
funktion();
}




Serieller Monitor:

 C!(j
7
1
!j
B1
11
10
B2
13
11
B3
17
100
B4
23
101

So würde ich es gerne machen:

C:
/*Array AUßERHALB einer Funktion*/
/*zweidimensionales Array an eine Funktion übergeben*/

int array_eins[3][21] = {
                            {
                             0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6                         
                            },

                            {
                             4,6,8,10,12,14,16
                            },

                            {
                             0b100000,0b100001,0b100010,0b100011,0b100100,
                             0b1000101,0b100110
                            }                                       
                        };




int array_zwei[3][15] = {
                            {
                             0xB0,0xB1,0xB2,0xB3,0xB4                         
                            },

                            {
                             7,11,13,17,23
                            },

                            {
                             0b0001,0b0010,0b0011,0b0100,0b0101
                            }                                       
                         };


void funktion(int feld)
{



 
int anzahl_im_array =sizeof(feld) / sizeof(int) / 3 / 3;

int erste_Zeile;
int zweite_Zeile;
int dritte_Zeile;

for(int zaehler = 0 ; zaehler<anzahl_im_array ; zaehler++)
  {

Serial.begin(115200);
/*Die Zahlen im Array ausgeben*/
Serial.println(" ");
Serial.println(" ");
Serial.println(feld[0][erste_Zeile],HEX);
Serial.println(feld[1][zweite_Zeile]);
Serial.println(feld[2][dritte_Zeile],BIN);

erste_Zeile++;
zweite_Zeile++;
dritte_Zeile++;
  }
}



void setup()
{
funktion(array_eins);
}
 

sheel

I love Asm
Hi

auch dein erster Code hat einige Probleme und Unklarheiten.

Zuerst einmal, sind die Arraywerte und -größen immer fix?

Dein Array ist als Größe 3x15 angegeben, hat aber nur 3x5 Elemente.

anzahl_im_array: Das geht so nicht. sizeof auf Arrays ist generell nicht wirklich ratsam (funktioniert nur in bestimmten Situationen), und auch wenn, woher kommt diese Formel? Pointergröße durch die 9-Fache Int-Größe, wieso?

erste_Zeile, zweite_Zeile und dritte_Zeile bekommen nie einen Wert, bevor dann auf feld[0][erste_Zeile] usw. zugegriffen wird. Solche Variablen sind nicht automatisch 0 oder so (zumindest nicht hier, in manchen anderen Fällen schon), das muss man hier selbst hinschreiben. Auswirkung ist im wesentlichen irgendwas beliebiges: Dein Programm kann etwas anderes machen als erwartet, oder abstürzen, oder sogar richtig funktionieren ... aber verlassen kann man sich aus nichts, und es kann auch bei jeder Ausfphrung was anderes passieren (wird hier nicht, aber kann in manchen Fällen).
...hat es dich nicht gewundert, dass "C!(j" eine hexadezimale Zahl sein soll?

Generell sind diese drei Variablen vermutlich nicht einmal nötig: Statt feld[0][erste_Zeile] könnte man auch feld[0][zaehler] nehmen...

Serial.begin sollte wohl eher aus der Schleife raus, darüber hin.

...

und zum zweiten Code: Mit den Sachen oben ausgebessert seh ich zurzeit kein Problem, aber:
Warum willst du überhaupt globale Variablen? Die meisten Leute vermeiden die lieber...
 

klicky

Grünschnabel
Hallo ,
erst mal Danke für die Antwort.
Ich habe einen Arduino Uno mit einem Grafikdisplay EA DOGM128 verbunden.
Darum wollte ich die selbsterdachten Pixelgrafiken in einem Array kodieren.
Die 2D-Arrays haben unterschiedliche Größe.
Nun möchte ich eine Funktion schreiben die so funktionieren soll:
C:
void setup()
{
funktion(array_eins);
}

Ich habe schon eine Figur auf das Display erfolgreich zur Anzeige gebracht. Aber das klappte nur weil das Array INNERHALB der Funktion lag.

Ach ja:

warum der serielle Monitor der Arduino Ide am Anfang C!(j ausspuckt statt B0 ist mir ebenfalls ein Rätzel.
 

cwriter

Erfahrenes Mitglied
Ich hänge mich dann mal ein.

Warum willst du überhaupt globale Variablen? Die meisten Leute vermeiden die lieber...
Arduino wurde nicht von Programmierern entwickelt ;-)
Aber bei den paar Kilobyte an Speicher kann man sich nicht allzu schlimm vertun.

Sehr unübersichtlich diese Zeiger.
Äh, ja. Ich mache dir einen Vorschlag und du kannst dann selbst entscheiden, ob das besser ist.
Momentan nutzt du 2D-Arrays (und willst sie an eine Funktion übergeben). Das Problem mit diesen Dingen ist aber, dass du normalerweise die Grösse im Voraus kennen musst. Wären deine verschiedenen Arrays gleich gross, könntest du schlicht ein int feld[X][Y] als Parameter verwenden.
Allerdings lügt die Sprache hier: Ein 2D-Array ist eigentlich ein 1D Array, nur syntaktisch gibt es 2 Indizes.
Was meine ich damit?
Sehen wir uns ein Beispiel an:
C:
int A[2][3];
/* Vorstellung: 3 Breit, 2 hoch (kann man auch umdrehen, sollte man aber nicht. Siehe Cachelines, falls es dich interessiert)
0 1 2
3 4 5
*/

/*Realität:
0 1 2 3 4 5
*/

int v = A[1][1];
//Vorstellung: Wähle die 4, da sie an der 1. Stelle von links und an der 1. Stelle von oben steht.
//Realität: Wähle v = Position von A[0][0] und gehe (1 * Breite) Schritte nach rechts und dann 1 Schritt nach rechts,
//also eigentlich A[1*3 + 1] == 4.

Diese Eigenschaft kannst du für deine Funktion benutzen. Gib einfach nur die Position des Anfangs des Arrays an die Funktion, also etwa so: int* loc = &(A[0][0]).
Nun fehlen uns aber die Grösseninformationen. Diese musst du entsprechend mitliefern.
Also sähe deine Funktion dann etwa so aus:
C:
void funktion(int* array, unsigned int w, unsigned int h)
{
Serial.begin(9600); //Bisschen eine anständigere Baudrate (warum brauchst du mehr als den Standard?)
for(size_t y = 0; y < h; y++) //Loop über die Zeilen
{
    for(size_t x = 0; x < w; x++)
    {
        int format = (y == 0) ? HEX : ((y ==1) ? DEC : BIN); //Bisschen Magic, lies über "Ternary Operator"
        Serial.println(array[y * w + x], format); //Diese Reihenfolge dürfte umgekehrt zu deiner sein. Einfach die Loops oben umkehren, dann sollte das passen (aber bist du sicher, dass du es anders haben willst? Performance ist massiv schlechter mit deiner Reihenfolge...)
    }
}

}

Und als Aufruf wäre es dann
C:
void setup()
{
funktion(&array_eins[0][0], 7, 3);
}
Dein Array ist falsch angegeben.
Du sagst, dass du einen Array mit 3 * 21 Elementen haben willst. Aber eigentlich willst du 3 * 7 = 21 Elemente haben.
Also als Grundlage für Arrays:
Ein Mehrdimensonaler Array ist ein Array von Arrays. Also ist
C:
int A[2][3];
Ein Array von 2 int Arrays von je 3 Elementen.

Gruss
cwriter
 

klicky

Grünschnabel
ja Danke :)
das hat mir schon weiter geholfen. Jetzt verstehe ich wie das Array im Speicher liegt.
C:
/*2D-Arrays*/

/* 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_Array[3][5] */
/* dann sind die Aufrufe: mein_Array[Zeile][Spalte]  */
/*                        mein_Array[0][Zeile * Breite + Spalte] gleichwertig.*/
                                           



int mein_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 anzahl_im_array =sizeof(feld) / sizeof(int) / 3;

void setup()
{
Serial.begin(9600);
//Serial.println(anzahl_im_array);


/*Die Zahlen im Array ausgeben*/
Serial.println(" ");
Serial.println(" ");
Serial.println(mein_Array[1][1]);

Serial.println(" ");
Serial.println(" ");
Serial.println(mein_Array[0][1 * 5 + 1]); /* mein_Array[][Zeile * Breite + Spalte] */
}





void loop(){}

als Ergebnis erhalte ich beidemale 29.


Stimmt, Array hatte ich falsch angegeben.
Aaaarg - Aber jetzt kommen die fiesen Zeiger :(
 

cwriter

Erfahrenes Mitglied
als Ergebnis erhalte ich beidemale 29.
Äh, ja, so geht's natürlich auch. Macht aber wenig Sinn. Wenn du ohnehin schon (syntaktische) 2D-Arrays hast, macht diese Art der Indizierung keinen Sinn. Es macht nur dann Sinn, wenn du einen logischen 2D Array in einen Syntaktischen 1D Array packen willst.

Aber jetzt kommen die fiesen Zeiger :(
Pointer sind nicht fies - schon gar nicht auf Mikrokontrollern, die nicht einmal einen Heap haben.
Es gibt nur 2 Dinge zu beachten:
1) Stelle sicher, dass du nicht ausserhalb des gültigen Bereichs schreibst/liest.
2) Caste nicht wild in der Gegend rum.

(Bei grossen Computern gibt es noch anderes zu beachten, aber wir sind ja bei Mikrokontrollern).

Gruss
cwriter
 

klicky

Grünschnabel
Sooo - Jetzt klappt es so wie ich es mir vorgestellt habe. Geht also auch ohne Zeiger.Noch mal vielen Dank für die Tipps.


C:
#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 zeige_Grafik(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");
}

AUSGABE am Terminal:



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