Hi,
hab ein großes Problem in c ein Programm zu schreiben, dass mir
eingelesene Text in einzelne Wörter teilen und diese in Array
abspeichern. Die Trennzeichen sind folgendermaßen definiert:
1)Leerzeichen 2)\n 3). 4),
Alle anderen Zeichen, die als Trennzeichen gelten könnten, sollen
vernachlässigt werden. Beim Speichern der Wörter, sollen die
Trennzeichen nicht mitgespeichert werden, sondern nur das Wort. Durch
mehrere Trennzeichen hintereinander dürfen auch keinen leeren Einträge
entstehen.
Brauche dringen Hilfe.
Mein Gedanke:
Es mit dem Stack zu machen. Immer wenn jetzt ein Trennzeichen auftritt,
dann speichere mir den eingelesenen Text in den nächsten Speicherbereich
von Stack. Nur habe ich nicht viel Erfahrung in c, sodass ich
Schwierigkeiten habe überhaupt anzufangen.
Es gibt aber auch eine Funktion strtok, aber es dürfen lediglich die
Bibliotheken stdio.h stdlib.h verwendet werden.
mfg
Simon A. schrieb:> Es gibt aber auch eine Funktion strtok, aber es dürfen lediglich die> Bibliotheken stdio.h stdlib.h verwendet werden.
Da aber das Schwierigste an der Aufgabe darin besteht, sich zu
überlegen, wie man die Übergabe der Parameter macht, bzw. wie bewusste
Funktion ihre Ergüsse das Aussenwelt mitteilt, könnte es sehr sinnvoll
sein, ein bißchen mit strtop bzw. strtok_r zu experimentieren und sich
ansehen, wie diese Funktionen den problenmatischen Teil lösen.
Der Rest ist nämlich einfach nur ein paar Schleifen.
Robert L. schrieb:>>strtok_r>>ihre Ergüsse das Aussenwelt mitteilt>> ich find das "gruselig" wie die das macht..
Find ich auch.
Aber wenn man es sich überlegt: Es gibt keine wirkliche Alternative,
wenn man innerhalb der Funktion keine dynamischen Allokierungen haben
will.
Hi,
danke für die ersten Informationen, werde mal probieren, was die zwei
Funktionen so machen.
Das das Programm mit dynamischen Speicherung auszuführen ist, ist mir
auch klar, da ja der eingegebene Text beliebig lang sein kann.
mfg
Klaus Wachtler schrieb:> du kennst den Sinn von Hausaufgaben?>> Naja, vielleicht findet sich ja wieder ein willfähriger Trottel.
Den Sinn von Hausaufgaben kenne ich, aber ist es schlimm zu fragen, wie
man das Programm angehen könnte, wenn man vorher nicht sehr viel mit
Programmierung zu tun hatte?
mfg
Simon A. schrieb:> Hi,>> danke für die ersten Informationen, werde mal probieren, was die zwei> Funktionen so machen.> Das das Programm mit dynamischen Speicherung auszuführen ist, ist mir> auch klar, da ja der eingegebene Text beliebig lang sein kann.
Genau das tun sie eben nicht.
Mit dynamischer Allokierung ist das alles trivial :-)
Simon A. schrieb:> Klaus Wachtler schrieb:>> du kennst den Sinn von Hausaufgaben?>>>> Naja, vielleicht findet sich ja wieder ein willfähriger Trottel.>> Den Sinn von Hausaufgaben kenne ich, aber ist es schlimm zu fragen, wie> man das Programm angehen könnte, wenn man vorher nicht sehr viel mit> Programmierung zu tun hatte?
OK.
Hinweis: Dein Stack Ansatz ist zu kompliziert. Oder hast du einen
dynamischen Stack verfügbar?
Merke: In C werden die Dinge richtig kompliziert, wenn 'es' dynamisch
wachsen und schrumpfen soll. Daher: Nimm das was du hast. Du hast einen
String. D.h. du hast ein Array. Kein Mensch sagt, dass in einem char
Array nur 1 String enthalten sein darf. In diesem Array darf es durchaus
mehrere Character-Sequenzen geben, die alle durch \0 Zeichen voneinander
getrennt sind. Alles was ein Verwender braucht, sind die Pointer auf den
jeweiligen Anfang einer Sequenz. Und genau die liefert strtok
sukzessive. Der Aufrufer von strtok ist dafür zuständig mit diesen
Pointern etwas zu machen (in einem Array zu speichern, die zugehörigen
Strings auszugeben, die zugehörigen Strings irgendwo anders zu
speichern, was auch immer - es ist auf jeden Fall sein Bier und nicht
das von strtok)
Karl Heinz Buchegger schrieb:>> Genau das tun sie eben nicht.
Muss mich entschuldigen, hab mich vielleicht nicht verständlich
ausgedrückt oder einfach zu pritiv, sodass es vielleicht anders
aufgenommen wurde. Ich werde die Funktionen strtok bzw. strtok_r einmal
ausprobieren.
Das ganze Programm (Hauptprogramm) soll so aufgebaut werden, dass ein
beliebig langer Text eingegeben werden kann. Dafür ist eben dynamische
Speicherverwaltung notwendig.
Ich hoffe, dass es jetzt passt.
Danke für die zusätzlichen Informationenen über meine Ansatz bzw.
strtok!!
Ich hab doch hier letztens nen schönen Tokenizer reingestellt **buddel**
wo war das noch gleich?
Edit:
Ahh, da isses ja :-)
Beitrag "Stringteilung in C"
Viel Spass!
Random ... schrieb:> Ich hab doch hier letztens nen schönen Tokenizer reingestellt **buddel**> wo war das noch gleich?>> Edit:> Ahh, da isses ja :-)>> Beitrag "Stringteilung in C">> Viel Spass!
Hi,
danke. Hab dein Programm auf meine Anforderungen umgeschrieben, aber
leider bekomme ich nicht den erwünschten Effekt.
if(*str == token) wurde geändert auf
if(*str == (' ') || *str ==(',') || *str == ('.') || *str == '\n')
sodass er jedes mal, wenn die Trennzeichen space; , ; . ; oder \n kommen
mir den String ausgibt.
Wenn nun die derzeitige Posiotion von *str ein Trennzeichen ist und die
vorherige Position auch ein Trennzeichen war, dann macht das Programm
ein zusätzliches leere Feld.
dest[0] = Hallo
dest[1] =
dest[2] = Welt
dest[3] =
dest[4] = Dies
dest[5] = ist
dest[6] = ein
dest[7] = Test
dest[8] = zum
dest[9] = Tokenizer
Eigentlich müsste ich ja nur abfragen, ob der Inhalt von *str (wo er
gerade hinzeigt) ein Trennzeichen enthält und der vorherige Inhalt auch
ein Trennzeichen war. Wenn das zutrifft, dann soll er den Schritt
überspringen.
Ich weiß nicht, ob meine Annahme jetzt richtig ist oder nicht. Hab jetzt
schon eine Zeit lang rumprobiert und komme auf keinen klaren Nenner.
Wäre sehr dankbar, wenn mir jemand weiterhelfen würde!
mfg
Du kannst dir ja auch ein Flag einführen, welches dir sagt: Ich habe ein
Nicht-Trennzeichen irgendwann mal vorgefunden.
Vor der Ausgabe eines Teilstrings (d.h. nach Erkennen eines
Trennzeichens) fragst du das Flag ab und weißt dann, ob es sich um einen
auszugebenden String handelt.
Oder ....
Bei der Ausgabe hast du einen Pointer auf den Stringanfang. Wenn nach
dem Erkennen eines Trennzeichens das nächste Zeichen nach dem
Stringanfang nicht ein \0 Zeichen ist, dann hast du einen String den du
ausgeben musst.
Karl Heinz Buchegger schrieb:> Bei der Ausgabe hast du einen Pointer auf den Stringanfang. Wenn nach> dem Erkennen eines Trennzeichens das nächste Zeichen nach dem> Stringanfang nicht ein \0 Zeichen ist, dann hast du einen String den du> ausgeben musst.
Das verstehe ich jetzt nicht so richtig. Also wenn nach dem Erkennen des
Trennzeichens das nächste kein \0 ist, dann muss ich es ausgeben. Aber
\0 ist ja der Nullpointer und der zeigt das Ende des strings an oder?
Was macht das für einen Sinn bezüglich dem Fall, dass er mir ein leeres
Feld erzeugt, wenn zwei Trennzeichen hintereinander kommen?
Steh irgendwie auf der Leitung.
mfg
Simon A. schrieb:
Du hast einen String
abcd;efg;;hijk
jetzt merkst du dir in einem Pointer wo ein (möglicher) String anfängt
abcd;efg;;hijk
^
1
mit einem 2.ten Pointer gehst du von dieser Position weiter, bis du auf
einen Terminator (;) stösst
abcd;efg;;hijk
^
1
^
2
kein Terminator
abcd;efg;;hijk
^^
12
kein Terminator
abcd;efg;;hijk
^ ^
1 2
kein Terminator
abcd;efg;;hijk
^ ^
1 2
kein Terminator
abcd;efg;;hijk
^ ^
1 2
Terminator gefunden.
Den Terminator ersetzt du durch ein \0
abcd0efg;;hijk0
^ ^
1 2
und damit ist der String, der beim 1ten Pointer anfängt ausgabebereit.
den ersten Pointer kannst du um 1 hinter dem 2.ten Pointer setzen, denn
am 2.ten Pointer kann jetzt kein String anfangen (dort ist ja das \0 das
du selber reingeschrieben hast.
abcd0efg;;hijk
^^
21
den 2.ten Pointer setzt du wieder wie vorher auf deiselbe Position wie
den ersten Pointer
abcd0efg;;hijk
^
1
^
2
und wieder geht die Suche nach einem Terminator weiter
kein Terminator
abcd0efg;;hijk
^^
12
kein Terminator
abcd0efg;;hijk
^ ^
1 2
kein Terminator
abcd0efg;;hijk
^ ^
1 2
Terminator
Wieder: das Zeichen unter dem 2.ten Pointer durch ein 0 Byte ersetzen,
damit da ein String entsteht
abcd0efg0;hijk
^ ^
1 2
und den String, der beim ersten Pointer anfängt ausgeben
Und schon läuft schon wieder das Weitersetzschema
1ten Pointer hinter den 2ten
abcd0efg0;hijk
^^
21
und 2ten Pointer auf die gleiche Position
abcd0efg0;hijk
^
1
^
2
Hoppla. Terminator gefunden
Wie auch vorher: Das Zeichen gegen ein 0 Byte austauschen
abcd0efg00hijk
^
1
^
2
und den String, der beim ersten Pointer beginnt, ausgeben.
Tja. Nur ist dieser String schon ein Leerstring. Wenn du dir also den
Stringanfang ansiehst (1ter Pointer) und dort schon eine \0 im Speicher
steht, dann hast du keinen auszugebenden String.
Einfach aufmalen und die Operation am Papier durchspielen. So entwickelt
man Ideen und Algorithmen.
Hi,
hab mein Programm jetzt fertig. Es splittet den eigelesenen Text, egal
wie viel Trennzeichen hintereinander sind und gibt diese aus.
Nur hab ich jetzt ein Problem und zwar:
Beispiel:
Hallo, World! Its a nice day,. to split words.
Dass Programm gibt mir alle neun Wörter einzeln aus. Super!
Mein Problem:
Hallo, World! Its a nice day,. to split words
Wenn ich jetzt das letzte Trennzeichen weglasse, dann gibt er mir das
letzte Wort nicht aus. Auch wenn ich nach EOF abfrage, gibt er das
letzte Wort nicht aus!
Ich hoffe mir kann jemand weiterhelfen.
mfg
Hi,
hab wieder einmal eine frage, und zwar:
Bei meinem Programm muss ich ja den eingelesenen String je nach
gewünschten Trennzeichen trennen. Zur Speicherung verwende ich
zweidimensionale Arrays. Hab jetzt aber ein Problem, ich kann zwar das
innere Array dynamisch allozieren, aber für das äußere hab ich immer
eine fixe Größe vorgegeben. Das äußere Array muss jetzt aber auch
dynamisch sein.
Hab schon eine Ahnung, wie ich es machen muss, aber bekomme es irgendwie
nicht hin.
Programmausschnitt:
Kann leider nicht den ganzen Quelltext einfügen, sondern nur Teile,
wegen der starken Plagiatkontrolle. Falls irgendwer den Code findet und
ihn eifach kopiert, dann schlägt sie an, und das führt zu
Schwierigkeiten.
Jetzt:
Eingabetext: Hallo, Welt!
char *single_words[BUFFERSIZE]; // BUFFERSIZE = 256
input_string = readInput(); //liest den String ein
splittet_words = splitInputIntoSingleWords(input_string, single_words);
int splitInputIntoSingleWords(char *input_string, char **single_words)
{
Hier mache ich nichts anderes als, dass ich den ganzen String mit
einer while Schleife durchgehe und bei jedem Durchgang abfrage, ob im
Pointer jetzt ein Trennzeichen steht oder nicht. Falls das der Fall ist,
dann speichere mir genau die Anzahl der Zeichen, die zwischen den beiden
Pointern stehen in das Array (für das erste Wort Array[0]=Hallo
Array[1]= Welt!), d.h., dass mein inneres Array bereits dynamisch ist.
}
Wie kann ich das bei mir mit einer bestimmten Größe vorgegebene äußere
Array auch dynamisch gestalten?
Mein Gedankengang, ich nehme eine Zählvariable, die mir die Anzahl der
Trennzeichen (Trennzeichen hintereinander gelten als ein Trennzeichen)
mitzählt und somit hätte ich dann genau die Anzahl der äußeren
benötigten.
Nur wie soll ich das jetzt in Programmcode umwandeln?
Könnte es dann so aussehen, dass ich schreibe:
char *single_words;
in der Funktion, dann
*single_words = (char*)malloc(BUFFERSIZE * sizeof(char));
Hier gebe ich dem array eine definierte Größe vor, die ich dann einfach
wieder realloziere.
Nur hab ich jetzt keine Ahnung, wie ich es reallozieren soll bzw. wie
diese Programmzeile aussieht, oder ob mein Quellcode völliger Blödsinn
ist.
Wäre über jegliche Hilfe sehr erfreut! Würde mich noch mehr freuen, wenn
mir jemand die drei oder mehr Zeilen schreibt!
mfg
ich würde das mit einer Statemaschine erledigen:
In einer (Zustands-)-Variablen abspeichern, ob das Programm sich inner-
oder außerhalb eines Wortes befindet.
Alle Zeichen in einer Loop einlesen und die Ein-/Austrittsbedingungen
für (Im-Wort/Außerhalb-Wort) definieren.
Hi,
hab es jetzt geschafft, dass mein Programm mir jedes der eingelesenen
Wörter nach bestimmten Trennzeichen teilt. Auch wenn zwei Trennzeichen
hintereinander kommen, übernimmt er es nicht, wie früher, dass es ein
leeres bzw. mit (null) befülltes Array liefert.
Jetzt hab ich nur ein Problem. Egal wie lange mein Text ist, immer an
der 4-ten Stelle, werden zusätzlich irgendwelche Zeichen eingefügt.
Main:
nicht angezeigte Programmcode:
Mit einer while gehe ich jedes Zeichen durch (daneben läuft eine
Zählvariable counter, die mit 1 initialisiert wurde). Falls ein
Trennzeichen gefunden wurde, führe folgendes aus (auszuführende Code
steht in der Funktion).
1
if(counter>1)
ist bei mir nun die Abfage, ob jetzt nach dem Trennzeichen noch ein
Trennzeichen auftritt. Wenn ja, dann speichert er es mir nicht in ein
Array, also entsteht kein leeres Feld.
Zum Beispiel: Hallo, ich heiße Simon A.
Feld[0] = Hallo
Feld[1] = ich
Feld[2] = heiße
Feld[3] = Simon�Ì h�Ì
Feld[4] = A
Ich weis einfach nicht warum er mir bei jedem 4-ten Wort immer
irgendwelche Zeichen zusätzlich einfügt!
Über Hilfe wäre ich sehr froh!
mfg
Simon A. schrieb:> Zum Beispiel: Hallo, ich heiße Simon A.>> Feld[0] = Hallo> Feld[1] = ich> Feld[2] = heiße> Feld[3] = Simon�Ì h�Ì> Feld[4] = A>> Ich weis einfach nicht warum er mir bei jedem 4-ten Wort immer> irgendwelche Zeichen zusätzlich einfügt!
Wo schreibst du in deinem Programm eigentlich das \0 hinter das letzte
Zeichen? Offensichtlich steht da beim dritten Feld was anderes.
Noch ein paar Anmerkungen zum Programm, die aber nichts mit dem Fehler
zu tun haben:
> int splitInputIntoSingleWords(char *input_string, char ***single_words)> {> int array_size = NULL;
NULL verwendet man nur für Zeiger. Schreibe hier einfach 0. Und als Typ
für Größen bietet sich size_t an:
1
size_tarray_size=0;
> (nicht angezeigter Programmcode)> if(counter > 1)> {> (*single_words) = realloc(*single_words, ++array_size *> sizeof(*single_words));
Hast du mal überlegt, was passiert, wenn realloc fehlschlägt? Außerdem
müßte es eigentlich sizeof **single_words heißen.
> (*single_words)[array_size -1] = (char *)malloc((counter *> sizeof(char)) + 1);
Den Cast nach char* solltest du bleiben lassen. Der ist eher schädlich
als nützlich. Und sizeof(char) ist per Definition immer 1.
> copyMemory((*single_words)[array_size - 1], input_string -> (counter - 1), (counter - 1));>> }> }>> nicht angezeigte Programmcode:> Mit einer while gehe ich jedes Zeichen durch (daneben läuft eine Zählvariable
counter, die
> mit 1 initialisiert wurde).
Wieso 1? Wenn also in deinem Teilstring 0 Zeichen stehen, hat counter so
den Wert 1. Durch deinen ganzen weiteren Code schleppst du diese 1 mit
und ziehst sie an jeder Stelle, wo du counter benutzt, wieder ab.
> Wo schreibst du in deinem Programm eigentlich das \0 hinter das letzte> Zeichen? Offensichtlich steht da beim dritten Feld was anderes.
Macht der Kompiler das \0 nicht von alleine und ich muss ihm nur um ein
Zeichen (Nullbyte) mehr Platz geben?
1
(*single_words)[array_size-1]=malloc((counter*
2
sizeof(char))+1);
Mit dem + 1 gebe ich ihm doch genau für ein Zeichen mehr Platz für das
\0.
> Hast du mal überlegt, was passiert, wenn realloc fehlschlägt? Außerdem> müßte es eigentlich sizeof **single_words heißen.
Ja, daran gedacht hab ich schon, aber eingebunden hab ich es nicht.
1
void*tmp=realloc(*single_words,++array_size*
2
sizeof(**single_words));
3
if(tmp)
4
*single_words=tmp;
5
else
6
FehlerbeimAllokierenaufgetreten
> Wieso 1? Wenn also in deinem Teilstring 0 Zeichen stehen, hat counter so> den Wert 1. Durch deinen ganzen weiteren Code schleppst du diese 1 mit> und ziehst sie an jeder Stelle, wo du counter benutzt, wieder ab.
Im Programm müssen vorher schon ein paar Error-Messages ausgegeben
werden. Wenn nun kein Zeichen im String steht, kommt das Programm
garnicht zur Ausführung der Funktion splitInputIntoSingleWords.
Hab den Counter deswegen mit 1 initialisiert, damit er das erste Zeichen
schon mitzählt. Wenn jetzt ein Trennzeichen aufgetreten ist, dann setzte
ich den counter wieder auf 0 und im Anschluss, wenn das zweite Zeichen
dran kommt erhöhe ich den counter wieder um 1. Wenn nun keine
Trennzeichen kommen, zählt er den counter pro Zeichen um 1 und bei
Auftreten eines Trennzeichens schreibt er mir die Zeichenkette bis zum
Trennzeichen rein. Falls jetzt zwei Trennzeichen hintereinander kommen,
wird nichts reingeschrieben, da garnicht dazu kommt
1
if(counter>1)
Wenn ich den counter mit 0 initialisiere, müsste ich alles umschreiben
aber wenn es etwas bringt (bei mir hat es leider nichts gebracht,
gleicher Fehler noch immer da) werde ich es machen.
mfg
Simon A. schrieb:>> Wo schreibst du in deinem Programm eigentlich das \0 hinter das letzte>> Zeichen? Offensichtlich steht da beim dritten Feld was anderes.>> Macht der Kompiler das \0 nicht von alleine
Woher soll er denn wissen, daß du das da haben willst? An welcher Stelle
im Code würdest du erwarten, daß es das macht?
> und ich muss ihm nur um ein> Zeichen (Nullbyte) mehr Platz geben?(*single_words)[array_size - 1] =
malloc((counter *
> sizeof(char)) + 1);> Mit dem + 1 gebe ich ihm doch genau für ein Zeichen mehr Platz für das> \0.
Du gibst ein Zeichen mehr Platz. Wenn du da nichts reinschreibst, bleibt
das drin stehen, was vor dem malloc an dieser Speicherstelle zufällig
gerade stand, genau wie bei jedem anderen Element dieses Arrays.
Rolf Magnus schrieb:> Simon A. schrieb:>>> Wo schreibst du in deinem Programm eigentlich das \0 hinter das letzte>>> Zeichen? Offensichtlich steht da beim dritten Feld was anderes.>>>> Macht der Kompiler das \0 nicht von alleine>> Woher soll er denn wissen, daß du das da haben willst? An welcher Stelle> im Code würdest du erwarten, daß es das macht?>
Das heißt ich muss beim Kopieren jedes einzelnen Wortes
eine Nullterminierung einfügen.
Kann mir irgendwie nicht vorstellen, wie ich die Nullterminierung hier
noch zusätzlich einfügen soll. Wäre über einen Ansatz sehr erfreut.