Verständnisfrage zu char*[]
-
Hallo Leute,
ich habe vor kurzem angefangen C++ zu lernen (Bachelor Informatik Studium) und komme mit Pointern noch nicht ganz klar. Vom programmieren per se habe ich Ahnung (einige Jahre mit C#), es geht also nur um reines C++ Verständnis.
Aber nun zu meiner eigentlichen Frage:
Ich habe ein Übungsaufgabe, in der ich alle Wörter aus einem String erkennen und zählen soll.
Die vorgegene Methodensignatur sieht so aus:int breakIntoWords(char *line, int maxwords, char *words[]);
line ist der String, der untersucht werden soll.
maxwords gibt die Arraylänge von words an.
words ist das Array, in das die einzelnen Wörter geschrieben werden sollen.
Der Rückgabewert ist die Anzahl der Wörter im String.Gehe ich recht in der Annahme dass
*words[]
ein Array von char-Pointern ist und kein Pointer auf ein char-Array?
Wenn ja würde dass ja bedeuten, dass ich innerhalb des Arrays nur die Pointer ändern kann und nicht den zugehörigen String, oder?
Mein Problem ist nun folgendes: wenn ich jetzt in diesem Array einfach einen Zeiger auf das zugehörige Wort im String habe, dann zeigen die ganzen Pointer ja auf Teilstrings, die dann zwar an dem entsprechenden Wort beginnen würden, aber halt den Rest des Satzes (oder Strings) auch, weil je kein Escapezeichen (\0) am Ende des Wortes steht.Ein Beispiel:
Angenommen der zu untersuchende String ist folgender: "Das ist ein Satz"
Würden die Wörter richtig erkannt, hätte ich 4 Pointer in dem Array. Beim ausgeben (z.B. printf) würde die Ausgabe doch so aussehen:
p1 -> "Das ist ein Satz"
p2 -> "ist ein Satz"
p3 -> "ein Satz"
p4 -> "Satz"
weil ja nur ein Escapezeichen ganz am Ende steht.Ich müsste ja eigentlich von jedem gefundenen Wort eine Kopie anlegen und an diese dann noch ein '\0' anhängen, damit das Wort auch zu einem gültigen String wird. Und genau dass kann ich mit einem
char*[]
nicht machen.
Ist das so korrekt?
-
Code4Fun schrieb:
Gehe ich recht in der Annahme dass
*words[]
ein Array von char-Pointern ist und kein Pointer auf ein char-Array?Weder noch. Das ist ein Zeiger auf einen Zeiger auf
char
. Das ist das gleiche wiechar **words
.Code4Fun schrieb:
Ich müsste ja eigentlich von jedem gefundenen Wort eine Kopie anlegen und an diese dann noch ein '\0' anhängen, damit das Wort auch zu einem gültigen String wird. Und genau dass kann ich mit einem
char*[]
nicht machen.
Ist das so korrekt?Doch, das geht über den Indexoperator.
words[0] = malloc(123);
Vielleicht hilft es dir für den Anfang, wenn du ein
typedef
verwendest:typedef char *c_string; int breakIntoWords(c_string line, int maxwords, c_string *words);
-
Warum ist
line
nichtchar const*
?
-
Arcoth schrieb:
Warum ist
line
nichtchar const*
?So kann er in
line
Whitespace durch'\0'
ersetzen und die Wortadressen inwords
sammeln -strtok
-mäßig.
-
Alles klar hab's jetzt verstanden.
Funktioniert wunderbar.
Vielen Dank./// Nachtrag
Warum kann ichwords
dann nicht einfach so initialisieren:char words[maxwords][20]
Wenn ich es so initialisiere und nach
char**
caste, bekomme ich einen Zugriffsfehler
-
1. Das ist keine Initialisierung sondern eine Definition.
2. Du brauchst keinarray of char[20]
sondern einarray of char *
-
1. Ja stimmt ist eine Definition
2. Wennchar* []
das gleiche ist wiechar**
warum ist dannchar**
nicht das gleiche wiechar[][]
??
-
// edit: Warning - 50% bullshit inside.
char * []
ist nicht dasselbe wie einchar **
aber einchar * []
zerfällt in einenchar **
. Ebenso ist einchar [][]
keinchar **
aber zerfällt in einen.Wenn du aber die Arrayelemente von
words
auf Wortanfänge inline
zeigen lassen willst, dann brauchst du ein Array of Pointers tochar
und kein Array of Arrays ofchar
.
-
char * [] ist nicht dasselbe wie ein char ** aber ein char * [] zerfällt in einen char **. Ebenso ist ein char [][] kein char ** aber zerfällt in einen.
Ich weiß nicht, was zerfällt in diesem Zusammenhang bedeuten soll?
char** und char[][] sind zwei verschiedene Typen, die nicht kompatible sind.
char* und char[] sind zwei verschiedene Typen, die kompatible sind und implizit konvertiert werden können.
-
coder777 schrieb:
char** und char[][] sind zwei verschiedene Typen, die nicht kompatible sind.
Ouch. Ja
-
Also jetzt bin ich verwirrt
TyRoXx schrieb:
Code4Fun schrieb:
Gehe ich recht in der Annahme dass
*words[]
ein Array von char-Pointern ist und kein Pointer auf ein char-Array?Weder noch. Das ist ein Zeiger auf einen Zeiger auf
char
. Das ist das gleiche wiechar **words
.das soll doch heißen, dass
char*[]
das gleiche ist wiechar**
, oder?coder777 schrieb:
char** und char[][] sind zwei verschiedene Typen, die nicht kompatible sind.
char* und char[] sind zwei verschiedene Typen, die kompatible sind und implizit konvertiert werden können.
Wenn ich also ein string in Form von
char* text;
habe, und ich greife mittext[i]
darauf zu, dann geht das, weil eine implizite Konvertierung statt findet?
Und wenn das jetzt beichar**
nicht funktioniert, wie greife ich dann auf die einzelnen Elemente zu?char** text; *(*(text + i) + j) = 'a'
So? Jetzt bin ich vollkommen durcheinander
Worin unterscheiden sich denn
char**
undchar[][]
und warum sind diese nicht kompatiebel zueinander?
-
char[][] gibt es nicht.
-
C(++) ist an der Stelle etwas verwirrend.
#include <type_traits> //so sind das verschiedene Typen static_assert(not std::is_same<int *, int[]>::value, ""); void f(int p[], int *q) { //und so ist das derselbe Typ! static_assert(std::is_same<decltype(q), decltype(p)>::value, ""); static_assert(std::is_same<int *, decltype(p)>::value, ""); int *p2 = p; //kompiliert nicht //int p3[] = p2; //geht aber mit einem echten Array int a[] = {1}; }
Es gibt übrigens gar kein
char[][]
.
GCC sagt das dazu:void f(char c[][])
error: declaration of 'c' as multidimensional array must have bounds for all dimensions except the first
-
Ja, char[][] gibt es nicht.
Ich habe es einfach als Abkürzung für
char Irgendwas[Irgendeinwert][Nocheinwert];
genommen.
Wenn man nun schreibt
char **ZeigerZeiger = Irgendwas;
wird sich der Compiler weigern. Der Punkt ist, dass die Daten eines Zeigers auf einen Zeiger eben anders organisiert sind als in einem zweidimensionalen Array.
Wenn man folgendes macht:
char **ZeigerZeiger = (char **) Irgendwas;
wird man unweigerlich Schiffbruch erleiden.
Man kann durchaus mittels ZeigerZeiger[i][j] auf den Inhalt zugreifen, aber die Berechnung um auf das einzelne Feld zu kommen ist eine andere als beim zweidimensionalen Array.
-
In C++ können Objekttypen vollständig (definiert) oder unvollständig sein.
Ein vollständiger Objekttyp verfügt u.a. über eine bekannte Größe und bekanntes Alignment, sizeof und align sind darauf anwendbar.
Für unvollständige Typen gilt das nicht, und davon gibt es wiederum 2 Arten: solche die vervollständigt werden können, und solche die niemals vollständig sind.
Typisches Beispiel für Ersteres ist eine Klasse, die deklariert, aber noch nicht definiert wurde.
Typisches Beispiel für Leteres ist der Typ void.Kommen wir zu Arrays.
Ein Array verfügt über einen Elementtyp und (optional) über eine feste Elementanzahl.
Elementtyp kann jeder Typ sein, der vollständig ist oder vervollständigt werden kann.
Ein Array mit bekannter Größe ist vollständig, wenn der Elementtyp vollständig ist; andernfalls unvollständig. Ein solcher unvollständiger Arraytyp wird vollständig, wenn der zugrundeliegende Elementtyp vollständig wird (also die betreffende Klasse definiert wird, bzw. rekursiv das Elementárray vollständig wird).Ein Arraytyp ohne bekannte Größe ist ein unvollständiger Typ, der nicht vervollständigt werden kann. Ein solcher Typ kann folglich niemals als Elementtyp eines anderen Arrays auftreten. Ausserdem ergeben sich ein paar interessante (z.T. ODR-relevante) Aspekte:
extern char x[]; using T = decltype(x); extern char x[1]; using U = decltype(x); static_assert( !std::is_same<T,U>{} );
Zu beachten ist, dass die Nichtvervollständigbarkeit dieser Typen kein Hindernis bei der Bildung von Zeigern ist.
void* oder char(*)[] sind kein Problem.Sonderregel Funktionsdeklarationen:
Wird in einer Funktionsdeklaration (und nur dort) der Typ eines Parameters als Array spezifiziert, so wird diese Spezifikation in die eines Zeigers auf den Elementtyp angepasst (die Arrayspezifikation muss immer noch legal sein: char[][] ist nicht erlaubt, obwohl char(*)[] möglich ist). Analog werden Paramter, die Funktionstyp haben, in Zeiger auf Funktionen angepasst. Eine vergleichbare Anpassung des Rückgabetypen erfolgt nicht, eine entsprechende Funktionsdeklaration, mit einem Array- oder Funktionsrückgabetyp ist schlicht illegal.
Diese Anpassung bedeutet nicht, dass Arrays mit Zeigern gleichzusetzen wären. Sie ist historisch bedingt, da C mit Funktionen und Arrays als Parameter nicht umgehen kann, es aber bequem sein kann, deren Deklarationssyntax im entsprechenden Kontext zu verwenden. Der entsprechenden Funktionsdeklaration wird somit nur eine vernünftige Bedeutung gegeben, da sie andernfalls schlicht fehlerhaft wäre.
-
coder777 schrieb:
Ja, char[][] gibt es nicht.
Ich habe es einfach als Abkürzung für
char Irgendwas[Irgendeinwert][Nocheinwert];
Und das ist keine gute Idee, eben weil [] bereits eine andere Bedeutung hat.
-
Okay ich denke jetzt habe ich es begriffen.
Falls nicht werdet ihr in den kommenden Tagen nochmal von mir hören
Vielen Dank euch allen.