Will man unbedingt die ganze Sache über die Argumentliste abwickeln,
dann geht die Sache so.
Nehmen wir mal einen einfacheren und weniger verwirrenden Fall her. Ein
int soll über die Argumentliste verändert werden.
So gehts nicht
1 | void foo( int i )
|
2 | {
|
3 | i = 5;
|
4 | }
|
5 |
|
6 | int main()
|
7 | {
|
8 | int k = 8;
|
9 | foo( k );
|
10 | // k ist immer noch 8
|
11 | }
|
warum gehts so nicht?
Weil die Funktion nur eine Kopie des Wertes in k bekommt. Wird die
Funktion aufgerufen, so wird die neue Variable i innerhalb der Funktion
erzeugt und sie bekommt eine Kopie des Wertes von k. Diese Kopie kann
die Funktion aber ändern wie sie lustig ist. Davon ändert sich k nicht.
Will man das erreichen, dann muss man die Adresse von k an foo
übergeben, damit foo über diese Adresse an k herankommt
1 | void foo( int* i )
|
2 | {
|
3 | *i = 5;
|
4 | }
|
5 |
|
6 | int main()
|
7 | {
|
8 | int k = 8;
|
9 | foo( &k );
|
10 | // jetzt hat k den Wert 5
|
11 | }
|
Der entscheidende Unterschied ist hier, dass in main
die Adresse der Variablen übergeben wird! Nur so, wenn die Funktion die
Speicheradresse von k hat, kann die Funktion auf die Variable k
zugreifen.
Die Funktion muss dafür als Argument einen Pointer haben
und muss über eine Derefernzierung
den Wert zuweisen.
Das allgemeine Schema lautet daher:
Gegeben sei ein Datentyp T.
Damit eine Funktion einen Wert vom Typ T beim Aufrufer verändern kann,
muss der Aufbau so aussehen
1 | void foo( T* ptr )
|
2 | {
|
3 | *ptr = irgend_ein_Wert_der_zu_T_passt;
|
4 | }
|
5 |
|
6 | int main()
|
7 | {
|
8 | T variable;
|
9 |
|
10 | foo( &variable );
|
11 | }
|
Das ist das allgemeine Schema, nach dem das läuft.
Nun. Im Falle des Fragestellers: Was ist der Datentyp T?
T ist in seinem Fall char*
Also setzen wir in das allgemeine Schema für T einfach mal char* ein
(einfach wie bei Copy&Paste alle T durch char* ersetzen):
1 | void foo( char** ptr )
|
2 | {
|
3 | *ptr = irgend_ein_Wert_der_zu_T_passt;
|
4 | }
|
5 |
|
6 | int main()
|
7 | {
|
8 | char* xyz;
|
9 | foo( &xyz );
|
10 | }
|
jetzt braucht man noch etwas vernünftiges für
"irgend_ein_Wert_der_zu_T_passt". Na, zb die Adresse des ersten Elements
des Arrays, vulgo "die Adresse des Arrays". Die einfache Nennung des
Arraynamens reicht dafür schon. Denn: Wird ein Array in dieser Form
benutzt (also ohne Indexoperation), dann steht der Name des Arrays für
seine Startadresse (vulgo: es degeneriert zu einem Pointer. Aber
Achtung: Ein Array IST deswegen noch lange kein Pointer. Ein Pointer ist
selbst eine Variable, die irgendwo im Speicher haust und eine Adresse
hat.)
1 | char test[5];
|
2 |
|
3 | void foo( char** ptr )
|
4 | {
|
5 | *ptr = test;
|
6 | }
|
7 |
|
8 | int main()
|
9 | {
|
10 | char* xyz;
|
11 | foo( &xyz );
|
12 | }
|
Willkommen in der 2-Stern Progammierung!
Lass dich nicht von char** verwirren. Die 2 Sterne entstehen dadurch,
dass du T durch char* ersetzen musst. Und daher wird dann T* zu char**
Die restlichen Probleme im Code wurden ja schon angesprochen.