Moing
In meinem Main habe ich einen Char-Array der von einer Funktion
verändert werden soll. Ich nehme schwer an dass ich seit gut 5 Stunden
auf einem total falschen Weg bin und vorlauter Bäume den Wald nicht mehr
sehe.
Gibt es eine "einfachere" und "sauberere" Lösung als das?
Die Aufgerufene Funktion
1
void Test_Function(void *Test_Char, int Text_Lenght)
Gibt es eine Möglichkeit diese Referenz in der Funktion wieder "normal"
über [x][y] adressieren zu können?
Gibt es eine Möglichkeit die Text_lenght (also die grösse der ersten
Dimension des Array) nicht mitgeben zu müssen?
Besten Dank für jeden Hinweis.
Interessant, wie das funktionieren soll...
Ich habe Dein Mini-Schnipsel-Programm mal etwas erweitert, damit man es
überhaupt einigermaßen durch einen Compiler bekommt:
array.c:21:5: warning: passing argument 1 of 'Test_Function' from incompatible pointer type [enabled by default]
4
array.c:4:6: note: expected 'char **' but argument is of type 'char (*)[20]'
Ausführen:
1
$ ./array
2
World
3
Segmentation fault
Spätestens jetzt solltest Du überlegen, wie Arrays im RAM organisiert
sind.
P.S.
Ich habe mir mal erlaubt, "Lenght" durch "Length" zu ersetzen.
Und so gehts:
Frank M. schrieb:> Michael .. schrieb:>>void Test_Function(char **Test_Char, int Text_Lenght)>> {>> Test_Char[x][y] = 'B';>> }>>> Interessant, wie das funktionieren soll...
Weiß jetzt nicht ob mich das beruhigen soll, aber diese "Lösung" hatte
ich auch schon mal gehabt heute...
Frank M. schrieb:> Ich habe mir mal erlaubt, "Lenght" durch "Length" zu ersetzen.
Na wenn schon auf dem Holzweg dann bitte richtig. Danke für den Hinweis.
Frank M. schrieb:> Und so gehts:#include <stdio.h>> #include <string.h>>> #define TEXT_LENGTH 20>> void Test_Function(char Test_Char[][TEXT_LENGTH], int x, int y)> {> Test_Char[x][y] = 'B';> }
Macht jedenfalls was es soll. Besten Dank Frank!
Sind meine beiden "Erkenntnisse" daraus richtig? (Aus Fehlern lernen ist
schön, aber für heute habe ich mehr gelernt als mit lieb wäre)
1.) Arrays werden in C/C++ eh immer als Referenz und nicht Kopie
übergeben. Daher ist eine Übergabe mit Pointer eh unnötig.
2.) Es muss nur die 2te Dimension vom Array spezifiziert werden, da die
Daten wie folgt im speicher liegen
arr[0][0]
arr[0][1]
arr[0][2]
arr[1][0]
arr[1][1]
daher spielt es keine Rolle wie gross die erste Dimension ist..
Johny_D schrieb:> 1.) Arrays werden in C/C++ eh immer als Referenz und nicht Kopie> übergeben. Daher ist eine Übergabe mit Pointer eh unnötig.
Soweit schon richtig. Es geht auch mit Pointern, aber dazu muss man dann
halt das Layout eines n-dimensionalen Arrays kennen - insbesondere die
konkreten n-1 Dimensionen, siehe auch 2). Dann kann man den Pointer auf
ein bestimmtes Element von [x][y] auch ausrechnen. Aber warum selbst die
Arbeit machen, soll der Compiler halt schuften. Der Arrayzugriff ist
deshalb auch nicht ineffektiver. Intern macht der Compiler (wenn er gut
ist und mehrere sequentielle Zugriffe auf nacheinanderfolgende Elemente
sieht) sogar selber Pointerzugriffe daraus.
> 2.) Es muss nur die 2te Dimension vom Array spezifiziert werden, da die> Daten wie folgt im speicher liegen
Korrekt. Allgemein ausgedrückt: Du musst dem Compiler n-1 Dimensionen
bekanntgeben.
> daher spielt es keine Rolle wie gross die erste Dimension ist..
Ja.
Johny_D schrieb:> 1.) Arrays werden in C/C++ eh immer als Referenz und nicht Kopie> übergeben. Daher ist eine Übergabe mit Pointer eh unnötig.
Exakt.
Der Name eines Arrays fungiert an den meisten Stellen als die Adresse
zum ersten Element des Arrays. Die Anzahl der Dimensionen ist dabei
unerheblich.
> 2.) Es muss nur die 2te Dimension vom Array spezifiziert werden, da die> Daten wie folgt im speicher liegen> arr[0][0]> arr[0][1]> arr[0][2]> arr[1][0]> arr[1][1]>> daher spielt es keine Rolle wie gross die erste Dimension ist..
exakt. Man sagt auch "der letzte Index läuft am schnellsten"
Du kannst es ja mal selbst ausprobieren:
Wenn alle Arrayalemente eines 2D Arrays hintereinander im Speicher
liegen
1
+---+---+---+---+---+---+
2
| | | | | | |
3
+---+---+---+---+---+---+
und die die Größe der 2.ten Dimension nicht kennst, wo beginnt dann die
2-te Zeile in diesem 2D Array
(ok, aus technischen Gründen kann das nur ein 2*3 oder ein 3*2 Array
sein. Nichts desto trotz: Beginnt die 2.te Zeile hier
1
+---+---+---+---+---+---+
2
| | | | | | |
3
+---+---+---+---+---+---+
4
^
5
|
oder beginnt sie hier
1
+---+---+---+---+---+---+
2
| | | | | | |
3
+---+---+---+---+---+---+
4
^
5
|
Welches ist in diesem 2D Array (von dem wir die Dimensionen nicht
kennen) das Element mit dem Index [1][1]? Wie rechnest du [1][1] um in
die Nummer des Elements in der linearen Abfolge?
Wenn ich dir aber sage, dass jede Zeile 3 Elemente lang ist, ist alles
klar.
)
Frank M. schrieb:> Karl H. schrieb:>> Nope.>> Falsch.>> Wurde oben durch praktische Anwendung schon gezeigt ;-)
Schön.
Die Frage ist nur warum das falsch ist.
Weil es sich bei einem
1
chartest[2][3];
nun mal nicht um ein Array von Pointer handelt, wobei jeder Pointer
wieder auf ein Array von 3 chars zeigt, also so etwas
1
+----+ +---+---+---+
2
| ------------------------->| | | |
3
+----+ +---+---+---+
4
| ----------+
5
+----+ | +---+---+---+
6
+----->| | | |
7
+---+---+---+
sondern um eine ganz normale lineare Abfolge von 6 Speicherzellen im
Speicher, deren Adressierung so gestaltet wird, dass die 2. Zeile am
3.ten Element im Speicher anfängt
1
+---+---+---+---+---+---+
2
| | | | | | |
3
+---+---+---+---+---+---+
Daher wäre char** völlig falsch.
Auf diese Idee zu kommen, zeigt dass da mal wieder wer (nicht du) auf
die schlampige Aussage reingefallen ist, wonach Arrays Pointer wären.
Dem ist nicht so!
Johny_D schrieb:> Gibt es eine Möglichkeit diese Referenz in der Funktion wieder "normal"> über [x][y] adressieren zu können?
J, wurde schon gezeigt
Johny_D schrieb:> Gibt es eine Möglichkeit die Text_lenght (also die grösse der ersten> Dimension des Array) nicht mitgeben zu müssen?
Darum wirst du nicht drumrum kommen.
Entweder in der Deklaration beim Paramter vom Array oder als
Extraparameter wie bei dir.
Aber du kannst das gecaste etwas eindämmen
Karl H. schrieb:> Der Name eines Arrays fungiert an den meisten Stellen als die Adresse> zum ersten Element des Arrays.
Das ist mir inzwischen auch klar. Die erste Variante die ich gepostet
hatte, funktionierte ja auch, abgesehen davon dass ich ein durcheinander
mit Zeilen und spalten gemacht habe und ich das ganze als "viel zu
unpraktisch um wahr zu sein" empfunden habe.
Karl H. schrieb:> Daher wäre char** völlig falsch.
Ich frage mich wie völlig falsch den das sein kann, während meiner
verzweifelten google Runde (mit ganz viel ehren Runden) habe ich diese
Lösung öfters angetroffen. Mit etwas Aufwand (den aber niemand will)
könnte man ja auch etwas in die Richtung machen...
Karl H. schrieb:> die schlampige Aussage reingefallen ist, wonach Arrays Pointer wären.> Dem ist nicht so!
Bei dem allem was im Internet rumgeistert kann man das aber schnell mal
glauben.
Denke die Investition in ein vernünftiges C/C++ Buch war keine blöde
idee. Sowohl zum lernen und als referenz, schon nur um zu wissen was
jetzt stimmt. Jetzt müsste es nur noch kommen :)
Dirk B. schrieb:> Aber du kannst das gecaste etwas eindämmen
Jup das würde es definitiv ein wenig übersichtlicher machen. Bleibe aber
trotzdem bei der Version von Frank, ist eigentlich genau das was ich
benötige.
Und zum Schluss ein Riesen Danke schön @all für die Hilfe!
Johny_D schrieb:>> Daher wäre char** völlig falsch.>> Ich frage mich wie völlig falsch den das sein kann
meine Zeichnung nicht gesehen?
Was ist dir am Unterschied zwischen der Datenstruktur A
1
+----+ +---+---+---+
2
| ------------------------->| | | |
3
+----+ +---+---+---+
4
| ----------+
5
+----+ | +---+---+---+
6
+----->| | | |
7
+---+---+---+
und der Datenstruktur B
1
+---+---+---+---+---+---+
2
| | | | | | |
3
+---+---+---+---+---+---+
unklar?
Ist doch klar ersichtlich, dass das im Speicher komplett anders
aufgebaut ist.
> verzweifelten google Runde (mit ganz viel ehren Runden) habe ich diese> Lösung öfters angetroffen.
Das es diese Lösung gibt, streitet ja auch keiner ab.
Nur wenn eine Funktion so aussieht
1
voidfoo(char**check)
2
{
3
...
4
}
dann kann ich ihr nicht einen
1
chartest[2][3];
vorsetzten. Denn die Funktion erwartet Datenstruktur A, der Aufrufer hat
aber 'nur' Datenstruktur B.
Im die Funktion zu befriedigen, müsste ich beispielsweise den Aufruf so
gestalten
1
{
2
char*data[2];
3
4
data[0]=malloc(3);
5
data[1]=malloc(3);
6
}
7
8
oder
9
10
{
11
char[]txt1="Si";
12
char[]txt2="No";
13
14
char*data[2]={txt1,txt2};
15
16
foo(data);
17
}
dann stimmen Aufrufer und Funktion darüber überein, wie die
Datenstruktur aussieht.
Das wird sogar sehr oft gemacht, weil es hier recht offensichtlich ist,
dass die Text eben nicht alle gleich lang sein müssen. Denn den Pointern
im Array ist es ja egal, wohin sie zeigen und wie lang das ist.
1
{
2
...
3
constchar*data[2]={"Hallo","du"};
4
...
5
}
Aber: Das ist nicht das, was ein
1
chartxt[2][3];
darstellt. Dessen Speicherlayout sieht ganz anders aus.
Johny_D schrieb:> Karl H. schrieb:>> Daher wäre char** völlig falsch.>> Ich frage mich wie völlig falsch den das sein kann, während meiner> verzweifelten google Runde (mit ganz viel ehren Runden) habe ich diese> Lösung öfters angetroffen. Mit etwas Aufwand (den aber niemand will)> könnte man ja auch etwas in die Richtung machen...
Ein Array von Pointern kannst du auch über zwei Klammerpaare
dereferenzieren.
Das wäre dann ein Doppelpointer.
Ein Beispiel wäre argv von main