Parameterübergabe von zweidimensionalen Feldern in Funktionen
1. Möglichkeit:
Funktionsaufruf mit Feld als Parameter: Die Adresse des nullten Elements des Feldes wird an die Funktion übergeben.
Beispiel:
Die Funktion ffmf soll die 2. Spalte der 1. Zeile eines zweidimensionalen Feldes auf den Wert von 197 setzen. Beachte: Nummerierung beginnt bei 0 !
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}}; } // gleichbedeutend mit: ffmf(zv); ffmf(&zv[0]);
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}}; ffmf(&zv[0]); Was wird also bei diesem Funktionsaufruf übergeben ? Die Adresse des 0. Elements (Komponente) des 2-dimensionalen Feldes zv. Aus welchen Elementen (Komponenten) besteht aber allgemein ein 2-dimensionales Feld ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Die Elemente eines zweidimensionalen Feldes sind EINDIMENSIONALE Felder
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Ein zweidimensionales Feld besteht also aus lauter eindimensionalen Feldern
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] welchen Speicher belegt z.B. also das 3. eindimensionale Feld (Element) von zv ? welchen Speicher belegt also z.B. das 2. eindimensionale Feld (Element) von zv ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] welchen Speicher belegt z.B. also das 1. eindimensionale Feld (Element) von zv ? welchen Speicher belegt also z.B. das 0. eindimensionale Feld (Element) von zv ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Wie groß ist jeweils ein eindimensionales Feld (farbig umrandetes Element) (Speichergröße in Byte) ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] zv ist ein zweidimensionales Feld. Es besteht aus den farbig umrandeten eindimensionalen Feldern mit jeweils der Größe 3*4 Byte.... weil ein eindimensionales Feld aus 3 integer Zahlen (zu je 4 Bytes) besteht.
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Wie kann man diese eindimensionalen Felder (farbig umrandeten Speicherbereiche) jeweils programmtechnisch "ansprechen" ?
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] zv[3] zv[2] zv[1] zv[0]
Wie kann man diese eindimensionalen Felder (farbig umrandeten Speicherbereiche) jeweils programmtechnisch in Pointerschreibweise "ansprechen" ?
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(zv+3) *(zv+2) *(zv+1) *(zv+0)*zv ist gleichbedeutend mit:
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(zv+3) *(zv+2) *(zv+1) *(zv+0) Der Inhalt von zv+0, zv+1, zv+2, zv+3, kurz zv+i ist jeweils ein Feld Ein Feld ist aber durch die Adresse seines nullten Elements gekennzeichnet. Also ist der Inhalt von zv+i, also *(zv+i) eine Adresse
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(zv+3 *(zv+2 *(zv+1 *(zv+0 *3*4) adressgenau ist also konkret: *3*4) = 0100 = 0112 = 0124 = 0136
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(zv+3 *(zv+2 *(zv+1 *(zv+0 *3*4) = 0100 = 0112 = 0124 = 0136 wie wird zv[1][2] in Pointerschreibweise adressgenau angesprochen ?
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(0112+2*4) *(zv+1 *3*4) +2*4)+2*4) programmtechnisch in Pointerschreibweise geschrieben: *(*(zv+1)+2)+2) *(zv+1*3*4) ersetze 0112 durch *(zv+1*3*4) = 197 *( =197
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(0112+2*4) *(zv+1 *3*4) +2*4)+2*4) programmtechnisch nicht in Pointerschreibweise geschrieben: *(*(zv+1)+2)+2) *(zv+1*3*4) ersetze 0112 durch *(zv+1*3*4) = 197 *( =197
zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *(0112+2*4) *(zv+1 *3*4) +2*4)+2*4) programmtechnisch nicht in Pointerschreibweise geschrieben: zv[1][2]=197 *(zv+1*3*4) ersetze 0112 durch *(zv+1*3*4) = 197 *(
Zurück zum Funktionsaufruf: ffmf(&zv[0]);
ffmf(&zv[0]); Auf was zeigt die Adresse von zv[0] ? (was ist der Inhalt von &zv[0]) Auf ein eindimensionales Feld der Länge 3
Wie muss also der formale Parameter in der Definition der Funktion ffmf deklariert werden ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ //...später... } int (*v)[3] Dies ist ein POINTER auf ein Feld der Länge 3
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; Die Funktion soll zv[1][2] auf 197 setzen. Wie muss dies also programmiert werden (in Pointerschreibweise)
Was geschieht genau beim Ablauf des Programms ? Wie wird der Parameter an die aufzurufende Funktion übergeben ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; *(*(0100+1*3*4)+2*4)=197 Zeigt auf ein Feld, also ist der Inhalt eine Adresse *4)*(=197 *0120=
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; *(*(0100+1*3*4)+2*4)=197 Zeigt auf ein Feld, also ist der Inhalt eine Adresse *4)*(=197 *0120=
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19} {20,21,22}} ffmf(&zv[0]); } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int (*v)[3] *(*(v+1)+2)=197; *(*(0100+1*3*4)+2*4)=197 Zeigt auf ein Feld, also ist der Inhalt eine Adresse *4)*(=197 *0120=
Aufgabe: Erweitern Sie die Funktion ffmf so, dass man nicht die 2.Spalte der 1.Zeile, sondern allgemein die s-te Spalte der z-ten Zeile von zv auf einen bestimmten Wert setzen kann. Erzeugen Sie einen Aufruf in main.
void ffmf1(int (*v)[3], int z, int s, int wert){ *(*(v+z)+s)=wert; // oder genauso möglich: // v[z][s]=wert; } void ffmf1(int (*v)[3], int z, int s, int wert); int main(){ int zv[4][3] = {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}}; ffmf1(&zv[0],1,2,197); }
Alternative Syntax
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmf(zv); } Alternative Syntax des formalen Parameters (kann genauso verwendet werden) : zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] void ffmf( ){ } int v[][3] *(*(v+1)+2)=197; // gleichbedeutend mit: v[1][2]=197
2. Möglichkeit:
Funktionsaufruf mit Pointer als Parameter: Die Adresse des Elements der 0. Spalte der 0. Zeile des zweidimensionalen Feldes wird an die Funktion übergeben.
Beispiel:
int main(){ int zv[4][3]= {{11,12,13},{14,15,16}, {17,18,19},{20,21,22}}; ffmp(&zv[0][0]); } Auf was zeigt die Adresse von zv[0][0] ? (was ist der Inhalt von &zv[0][0]) Auf eine integer Zahl
Wie muss also der formale Parameter in der Definition der Funktion deklariert werden ?
void ffmp( ){ } int main(){ int zv[4][3]= {{11,12,13},{14,15,16}, {17,18,19},{20,21,22}}; ffmp(&zv[0][0]); } int *p Welches Element von zv wird also verändert Diese Funktion ffmp soll mit Hilfe der Pointerschreibweise die 2. Spalte der 1. Zeile von zv auf 197 abändern. Wie wird das programmiert ? Beachte: Nummerierung beginnt bei 0 ! Dies ist ein POINTER auf ein int
void ffmp( ){ *(p+5)=197; } int main(){ int zv[4][3]= {{11,12,13},{14,15,16}, {17,18,19},{20,21,22}}; ffmp(&zv[0][0]); } int *p Was müsste man abändern, wenn nicht die 2.Spalte der 1.Zeile, sondern allgemein die s-te Spalte der z-ten Zeile von zv auf 197 gesetzt werden soll ? 16 ist das 5. Element im Feld zv. Dieses bekommt den neuen Wert 197
void ffmp( ){ *(p+z*3+s)=197; } int main(){ int zv[4][3]= {{11,12,13},{14,15,16}, {17,18,19},{20,21,22}}; ffmp(&zv[0][0]); } int *p Warum 3 ? Weil dies die Länge einer Spalte ist !! Wer sollte den Wert von z und s festlegen ? Wo ist es also sinnvoll z und s zu deklarieren ? Warum ist das Programm noch syntaktisch falsch ? Weil z und s nicht deklariert sind !
void ffmp( ){ *(p+z*3+s)=197; } int main(){ int zv[4][3]= {{11,12,13},{14,15,16}, {17,18,19},{20,21,22}}; ffmp(&zv[0][0]); } int *p, int z, int s Der Programmierer, der die Funktion ffmp nutzen will. Wo muss p, z und s deklariert werden ? Warum ist der Aufruf syntaktsch falsch ? Weil der Aufruf aus 3 Parametern bestehen muss.
Was geschieht genau beim Ablauf des Programms ? Wie wird der Parameter an die aufzurufende Funktion übergeben ?
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2]
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] 0100
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] *3*4*4 +2 *4*4= Weil ein Element von zv 4 Byte (integer) benötigt !
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } *3*4*4 +2 *4*4= zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Weil ein Element von zv 4 Byte (integer) benötigt !
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} ffmp(&zv[0][0]); } void ffmp(int *p){ *(p+1*3+2)=197; } *3*4*4 +2 *4*4= zv[0][0] zv[0][1] zv[0][2] zv[1][0] zv[1][1] zv[1][2] zv[2][0] zv[2][1] zv[2][2] zv[3][0] zv[3][1] zv[3][2] Weil ein Element von zv 4 Byte (integer) benötigt !
Aufgabe: Erweitern Sie die Funktion ffmp so, dass man ganz allgemein die s-te Spalte der z-ten Zeile eines zweidimensionalen Feldes mit der Spaltenlänge slen auf einen bestimmten Wert setzen kann. Erzeugen Sie einen Aufruf in main.
int main(){ int zv[4][3]= {{11,12,13}, {14,15,16}, {17,18,19}, {20,21,22}} // Beispiel eines Aufrufs: ffmp(&zv[0][0], 1, 2, 3, 197); } void ffmp(int *p, int z, int s, int slen, int wert){ *(p+z*slen+s)=wert; }