Wörter alphabetisch ordnen
-
Da läuft bei dir noch etwas durcheinander.
Bei
char * Stringarray; // neu Stringarray = (char *) malloc(100); //
hast du kein Stringarray, sondern nur einen Speicher für einen String.
Das was du mit
char *strs[NUMBER_OF_STRINGS];
haben wolltest, musst du mit einem Doppelzeiger machenchar **Stringarray; // neu Stringarray = malloc(100 * sizeof(*Stringarray)); // Jetzt hast du Platz für 100 Zeiger auf char*
Da bleibt noch die Frage, wo die Zeiger hinzeigen sollen.
Im Augenblick sieht es so aus, dass die Zeiger noch nach text verweisen.
Die Wöerter sind dadurch nicht Nullterminiert.
-
size_t woerter(char *text) { size_t word_count = 0; int is_space, was_space; char **Stringarray; // neu Stringarray = malloc(100 * sizeof(*Stringarray)); // neu for (was_space = 1; *text; was_space = is_space) if (!(is_space = isspace(*text++)) && was_space) Stringarray[word_count] = *text; // neu printf("%s", Stringarray); // neu free(Stringarray); // neu // gibt mir nun z.B. beim Wort "test" nur den Buchstaben e aus. word_count++; return word_count; }
Visual Studio meckert bei der Zuweisung: "...."void *" kann keiner Entität vom Typ char ** zugewiesen werden bzw "char" kann keiner Entität vom Typ "char *" zugewiesen werden"
Allerdings läuft das Programm problemlos durch.
Durch die Änderung gibt er mir nur den Buchstaben e aus beim Wort test, bei test test auch nur e, also immer die zweite Stelle.
Das mit dem Pointer verstehe ich, also im Moment erstelle ich eigentlich nur einen String, den es in c ja so nicht gibt, also ein char Array mit der Länge meiner Eingabe.
Mit (Spekulation)
strcpy(Stringarray, text)
müsste ja dann immer ein Array gefüllt werden, oder denke ich da falsch?
-
Bei Fehlermeldungen ist die Angabe der dazu gehörigen Zeilen-/Spaltennummer zwingend, damit man auch weiß, wo der Fehler auftritt.
`Stringarray ist vom Typ char**
Stringarray[word_count] ist vom Typ char*
text ist vom Typ char*
*text ist vom Typ char`
Sinnvoll ist hier eigentlich nur die Zuweisung gleicher Typen.
size_t woerter(char *text) { size_t word_count = 0; int is_space, was_space; char **Stringarray; Stringarray = malloc(100 * sizeof(*Stringarray)); for (was_space = 1; *text; was_space = is_space) if (!(is_space = isspace(*text++)) && was_space) Stringarray[word_count] = *text; // char* = char -> passt nicht // hier ist die for-Schleife vorbei printf("%s", Stringarray);// printf erwartet char*, bekommt aber char** -> passt nicht free(Stringarray); word_count++; // sollte das nicht in der Schleife / im if sein? return word_count; }
C-Tabaluga schrieb:
Mit (Spekulation)
strcpy(Stringarray, text)
müsste ja dann immer ein Array gefüllt werden, oder denke ich da falsch?
Typproblem siehe oben.
Und du brauchst auch Speicher in den du kopieren darfst. Den hast du mit dem einen malloc noch nicht bekommen.Mit dem malloc in Zeile 8 hast du Platz für 100 Zeiger auf char*. Den Speicher wo die dann hin zeigen hast du damit noch nicht.
-
Sorry, das mit der Zeilesache, soweit hätte ich denken müssen.
size_t woerter(char *text) { size_t word_count = 0; int is_space, was_space; char **Stringarray; Stringarray = malloc(100 * sizeof(*Stringarray)); // hier befindet sich ein Fehler (falsche Typzuweisung) for (was_space = 1; *text; was_space = is_space) { if (!(is_space = isspace(*text++)) && was_space) { word_count++; Stringarray[word_count] = text; // damit will ich ein Wort einzeln deklarieren und in ein char Array Stringarray[i] legen bzw später kopieren // free(Stringarray); // Durch das malloc soll man das Array bei nicht benutztem Speicherplatz wieder räumen. } } printf("%s", Stringarray); // das soll testweise ausgeben, ob der Compiler meinen Wunsch erfüllt return word_count; }
Deklarationsprobleme bis auf das im Kommentar erwähnte nun beseitigt.
Erwartet wird von mir als Ausgabe bei der Eingabe test also test. Bei Eingabe von test bekomme ich aber nur kryptische Zeichen und =.
Irgendwo häng ich fest, als dass ich wegkomme von dem Fehler. Das Behandlen von Strings fällt mir schwerer als ich dachte in C, aber es immer schön solche Leute wie euch zu haben, die einem bei der größten Verzweiflung helfen. Danke dafür!
-
Deine Ausgabe ist falsch
DirkB schrieb:
printf("%s", Stringarray);// printf erwartet char*, bekommt aber char** -> passt nicht
Dein Stringarray ist ein Feld, das 100 Zeiger auf
char
-Zeiger speichern kann.text ist ein Array von 1024
char
.Nehmen wir mal an, text fängt an der Speicheradresse 10000 an.
Der Speicher denmalloc
für Stringarray reserviert hat liegt bei 44444. In Stringarray ist also 44444 gespeichert.Nach deinem Programm sollte das dann so aussehen:
char text[1024] = "Hallo Welt, dies ist ein Text" ^ ^ ^ ^ ^ ^ Stringarray[0] = 10000 -+ | | | | | // bei Adresse 44444 Stringarray[1] = 10006 -------+ | | | | // bei Adresse 44448 Stringarray[2] = 10012 -------------+ | | | // bei Adresse 44452 Stringarray[3] = 10017 ------------------+ | | // bei Adresse 44456 Stringarray[4] = 10021 ----------------------+ | // bei Adresse 44460 Stringarray[5] = 10025 --------------------------+ // bei Adresse 44464
Wenn du jetzt das "ein" haben willst, dann musst du an
printf
dei Anfangsadresse (10021) übergeben.
Diese ist in Stringarray[4] gespeichert.
Durch das printf("%s", Stringarray); bekommtprintf
aber die Adresse 44444. Da stehen aber nur Adressen und kein sinnvoller Text.Wie du auch siehst, sind die Wörter weiterhin in text abgelegt und
DirkB schrieb:
Die Wöerter sind dadurch nicht Nullterminiert.
Stringarray[4] liefert als nicht nur "ein" sondern "ein Text".
-
Okay, das mit der Ausgabe ist mir nun klar.
printf("%s", Stringarray[1]);
Beim Wort test gibt er mir dann est aus. Also noch ein kleiner Zuweisungfehler mit dem ersten Wort. Wie du auch richtig sagst, gibt er mir bei test test z.B. est test aus, also er trennt nicht, was mit der von dir erwähnten Nullterminierung zusammenhängt. Diesbezüglich habe ich mich versucht zu informieren, aber ich finde da keinen Ansatz, der mir hierbei weiterhelfen würde.
Wenn ich z.B. sagen würde: text = 0 oder text = ""; dann gibt er mir trotzdem immer alle Wörter aus.
Ich versteh, was du meinst und was du erreichen willst, aber ich weiß nicht, wie ichs umsetzen soll.
Ich muss ja erst sagen
Stringarray[word_count] = text;
aber das ist ja eigentlich schon zu spät, weil da gibt er ja auf Platz 1 den ganzen Text ein. Also muss irgendwo vorher getrennt werden bzw. der Wert von text wieder auf null gesetzt werden.
-
Kann mir jemand nen Tipp geben?
-
Das mit dem "est" mag daran liegen, dass du bei *isspace(test++) schon den Postinkrement hast.
Für die einzelnen Wörter gibt es mehrer Möglichkeiten:
Du schreibst an die Stellen, wo ein Whitespace ist, eine '\0' in text.
Dann ist text aber zerstört. (so macht es die Standardfunktionstrtok
)Oder du beschaffst dir für die Wörter auch Speicher mit
malloc
und kopierst die Wörter dann da rein.Nimm mal den Debugger und geh im Einzelschritt durch die Funktion. Lass dir dabei die Variablen anzeigen.
Dann siehst du, was wann wo passiert.
-
Grundidee habe ich verstanden und würde ich so umsetzen:
#include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <conio.h> size_t woerter(char *text) { size_t word_count = 0; int a; a = 100; int is_space; int was_space; char **Stringarray; // neu Stringarray = (char**) malloc(100 * sizeof(*Stringarray)); char *woerter; woerter = (char*) malloc (a * sizeof(woerter)); // hier will ich die wörter reinlegen for (was_space = 1; *text; was_space = is_space) { if (!(is_space = isspace(*text++)) && was_space) { *text--; strcpy(woerter, text); //würde der so richtig kopieren? word_count++; } } return word_count; } int main(void) { int i = 0; char text[100]; puts("Geben sie beliebige Woerter ein:"); fgets(text, sizeof(text) / sizeof(text[0]), stdin); // Verwendung der Funktion printf("Es sind %d Woerter\n", woerter(text)); getch(); return 0; }
Ich gebe mehrere Wörter ein und er gibt mir nur das erste aus. Wie kann ich das nun wiederholen, dass er im Array eins weitergeht?Also ich weiß im Moment noch nicht, wie ich das jetzt in das Stringarray reinmachen soll...
-
C-Tabaluga schrieb:
char *woerter; woerter = (char*) malloc (a * sizeof(woerter)); // hier will ich die wörter reinlegen
Bei dem
sizeof
in demmalloc
wird nicht ein * weg gelassen, sondern es wird einmal dereferenziert.
Du willst ja die Größe von dem Element bestimmen, auf den woerter zeigt.
Also kommt da ein * hin. : *sizeof(woerter)
Du kannst auch sizeof(woerter[0]) (und auch Stringarray = malloc(100 * sizeof(Stringarray[0])); )machen, wenn dir das einsichtiger ist.Du hast jetzt einen Speicherbereich für alle Wörter. Da wäre es am einfachsten du machst ein strcpy(woerter, text); und veränderst die Trennzeichen dann in woerter.
Eigentlich war das aber so gedacht, dass du für jedes gefundene Wort Speicher anforderst und dieses dann von text in den Speicher kopierst. In der Schleife.
C-Tabaluga schrieb:
*text--; strcpy(woerter, text); //würde der so richtig kopieren?
Ein
strcpy(woerter, text-1);
macht es auch, ohne dass du an text rum spielst.
Du kommst hier mit nur einem
char*
nicht mehr weiter. Du musst dir den Anfang vom Wort merken und dann noch einchar*
haben, der die Zeichen untersucht (dein bisheriges text).Die Wortlänge ergibt sich dann aus der Differenz der beiden Zeiger.
Wenn du für den Wortspeicher
calloc
nimmst, kannst du die Wörter auch mitstrncpy
(oderstrncat
) da hin kopieren.
calloc
löscht den Speicher gleich.strncpy
kopiert keine '\0', wenn die Anzahl der Zu kopierenden Zeichen erreicht ist. Wenn das Ziel leer ist, iststrcat
wiestrcpy
.strncat
hängt aber immer eine '\0' an.
(Ich hoffe du hast die n bei den strncpy und strncat bemerkt)
-
C-Tabaluga schrieb:
Ich gebe mehrere Wörter ein und er gibt mir nur das erste aus. Wie kann ich das nun wiederholen, dass er im Array eins weitergeht?Also ich weiß im Moment noch nicht, wie ich das jetzt in das Stringarray reinmachen soll...
Na mit dem word_count. Das stand doch schon da.
Stringarray ist ein Array mit Zeigern auf char*char text[1024] = "Hallo Welt, dies ist ein Text" vvvvv ||||| |||| ||| ||| |||| Stringarray[0] = 20000 "Hallo"vvvvv |||| ||| ||| |||| Stringarray[1] = 20032 "Welt,"vvvv ||| ||| |||| Stringarray[2] = 20064 "dies"vvv ||| |||| Stringarray[3] = 20096 "ist"vvv |||| Stringarray[4] = 20128 "ein"vvvv Stringarray[5] = 20150 "Text" Stringarray[6] = NULL // als Endekennung Die Adressen ab 20000 (Beispiel) werden alle einzeln mit malloc/calloc beschafft. Die vvvv stellen das kopieren mit strncpy dar
Du musst hier die Indizes von Stringarray durch word_count ersetzen.
-
Ganz schön gewöhnungsbedürftig mit 2D Arrays und Pointern zu arbeiten.
size_t woerter(char *text) { size_t word_count = 0; int is_space; int was_space; int a = 100; char *woerter; char **Stringarray; int i = 100; int zeichenzahl = 0; //zum buchstaben zählen Stringarray = (char**) malloc(100 * sizeof(*Stringarray)); //sizeof(Stringarray[0]) woerter = (char*) calloc (100, 100 * sizeof(*woerter)); // sizeof(woerter[0]) calloc, weil nach kopiervorgang wieder leer for (was_space = 1; *text; was_space = is_space) { zeichenzahl++; if (!(is_space = isspace(*text++)) && was_space) { strcpy(woerter, text-1); // kopiert das Wort in woerter strncpy(Stringarray[word_count], woerter, zeichenzahl); //von woerter ins stringarray, woerter ist danach wieder frei zeichenzahl = 0; //zeichenzahl wieder auf 0 setzen word_count++; } } printf("%s", Stringarray[1]); return word_count; }
Ich zähl also die Zeichen bis zum Leerzeichen, dann kopier ich den darin befindlichen Inhalt in woerter. Von woerter gehts weiter ins Stringarray. woerter ist danach wieder leer. Stopp.
Nun müsste ich mir gemerkt haben, wo ich war. Also evt noch einen zusätzlichen Counter einbauen. Da soll strncpy dann wieder kopieren. Dann sollte das befüllen klappen. Im Moment gehe ich nur noch etwas unsanft mit den Schreibrechten um, aber das sollte sich danach noch beheben lassen.
-
C-Tabaluga schrieb:
Von woerter gehts weiter ins Stringarray. woerter ist danach wieder leer.
Wie kommst du darauf, dass woerter wieder leer ist?
C-Tabaluga schrieb:
strncpy(Stringarray[word_count], woerter, zeichenzahl);
klappt nicht, da bei Stringarray[word_count] kein Speicher hinterlegt ist. Dieser Speicher sollte eigentlich woerter sein.
Stringarray enthält nur die Zeiger auf den Speicher, wo die Wöerter abgelegt sind.
Den Speicher musst du aber erst besorgen. Für jedes Wort neu. Da passiert nichts automatisch.Zudem zeigt text auf das Ende vom Wort. Das ist für das kopieren etwas schlecht.
Pseudo-Speicher für die Wortliste holen // das ist Stringarray solange noch Zeichen im Text sind Ist das ein Wortanfang? dann Stelle merken Ist das ein Wortaende? dann Länge vom Wort berechnen // zeichenzahl oder Wortanfang-Wortende Speicher für Wort holen (Länge +1) // calloc Wort in Speicher kopieren // strncpy(Speicher,Wortanfang,Länge) Wort terminieren // Speicher[Länge] = '\0'; Speicher in Stringarray eintragen // Stringarray[word_count] = Speicher_den_du_von_calloc_hast word_count erhöhen. nächstes Zeichen im Text nehmen Stringarray[word_count] = NULL // Endemarkierung
Was noch fehlt ist die Überprüfung, ob Stringarray voll ist (mehr als 99 Wörter)
Wenn du das mit der Endemarkierung machst, dann ist die Ausgabe auch ganz einfach:
for(i=0;Stringarray[i];i++) puts(Stringarray[i]);
Nochmal zu calloc. Du hast da Platz für 100*100 Zeichen reserviert.
Der erste Parameter gibt die Anzahl der Elemente an, der zweite die Größe der Elemnte.
Diese beiden Werte werden multipliziert.calloc (Länge, sizeof(*woerter)); // so ist es gedacht //oder calloc (sizeof(*woerter),Länge); // geht auch
Schnapp dir endlich mal den Debugger.