Abspeichern einer Terminaleingabe als String
-
Versuch mich gerade ins C einzuarbeiten.
Im "The C Programming Language" kommt früh (zu früh) die Aufgabe, ein Programm zu erstellen, welches das Umkehren einer Eingabe erledigt.Nun ist das Arbeiten mit Strings in C alles andere als intuitiv (finde ich).
Das Umkehren ist ja keine Sache WENN man den String dann endlich mal hat, und genau da happerts.Über eine Vielzahl von Webseiten hab dies hier gefunden und zu dem da vermurkst:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]){ while(1){ char *str; int status = readLineToStr(&str); if(status < 0) printf("There was an error processing your input. (%d)", status); else{ //reverseChar(&str); printf("%s", str); free(str); } }//end while return 0; }//end main /*readLineToStr: returns a string representing a console readLineToStr input*/ int readLineToStr(char *target){ #define INITSPACE 100 char *currChar = malloc(INITSPACE); char *strPointer = currChar; int c, space, available = space = INITSPACE; while(1){ c = fgetc(stdin); //nextChar if(c == EOF || c == '\n') //break on end of file OR on linebreak break; if(--available == 0){ //"extend" string when necessary available = space; char *extStr = realloc(strPointer, space *= 2); /*note to self: reallocation returns new mem.block address*/ if(extStr == NULL){ //abort when reallocation fails free(strPointer); return -1; }//end if(extStr) currChar = extStr + (currChar - strPointer); strPointer = extStr; }//end if(!available) *currChar++ = c; }//end while(1) *currChar = '\0'; //end of string target = strPointer; return 0; }//end readLineToStr
Das Resultat, wenn ich das in cygwin kompiliere (gcc), sieht so aus:
http://g14.img-up.net/lineread-e237d.JPGSprich er liefert mir bei der ersten Eingabe ein "Aborted (Speicherabzug geschrieben)".
Die entsprecende .stackdump sieht so aus:Stack trace: Frame Function Args (Leerzeile, die das Forum aus dem code nimmt)
Und ich hab keine Ahnung, was schief läuft.
Mag mir da wohl wer helfen?
-
Übertreibst du da nicht etwas für den Anfang?
Nimm ein char-Array mit genug Platz und lese den String mit scanf ein.
Meinetwegen auch mit gets (danach aber nie wieder).
-
Wollte ich auch vorschlagen. Bzw. fgets, das produziert keine Sicherheitslücke wie gets oder ein unvorsichtig eingesetztes scanf.
-
int readLineToStr(char **target){
und später
*target = strPointer;
Weil &str die Adresse eines char*, mithin ein char** ist und du nicht den lokalen Parameter target, sondern das worauf er zeigt (nämlich str), verändern willst.
Protip: Ruf gcc mit -Wall -Wextra -pedantic auf, dann sollte der bei solchen Dingen gleich meckern.
-
fgets hat noch das '\n' am Ende. Ist für einen Anfänger auch verwirrend.
-
User1291 schrieb:
Und ich hab keine Ahnung, was schief läuft.
Mag mir da wohl wer helfen?wenn du die verlinkte funktion so übernehmen würdest, wie sie dort steht, dann hättest du schon mal mehr aussicht auf erfolg.
dort wird ein char* zurückgegeben. das ist ein zeiger auf den anfang der eingelesenen daten.
so wie du sie benutzt, kann dein zeiger char *str; diese info nicht erhalten.
-
seldon schrieb:
`
int readLineToStr(char **target){
und später
*target = strPointer;
`
Weil &str die Adresse eines char*, mithin ein char** ist und du nicht den lokalen Parameter target, sondern das worauf er zeigt (nämlich str), verändern willst.Protip: Ruf gcc mit -Wall -Wextra -pedantic auf, dann sollte der bei solchen Dingen gleich meckern.
Danke dir, so funktioniert das Einlesen.
Und nun hab ich auch (endlich) das mit den Pointern einigermassen begriffen.
Wäre ansonsten wohl doch recht schwer geworden:/*reverseStr: reverses char order of target string*/ int reverseStr(char **target){ char *i, *j, *it; it = i = j = *target; char c; while((c = *it) != '\0') it = ++j; /*note to self: j is now pointing to '\0'*/ while(i < --j){ char temp = *i; *i = *j; *j = temp; i++; }//end while(i,j) return 0; }//end reverseStr
Besten Dank (auch für die ... wie auch immer man die Bindestrich-Optionen bei Kommandzeilebefehlen nennt
)
stream buffer fan schrieb:
wenn du die verlinkte funktion so übernehmen würdest, wie sie dort steht, dann hättest du schon mal mehr aussicht auf erfolg.
Mag sein, aber hätt ich das schlicht ge-copy-pasted, dann hätt ich jetzt nichts gelernt.
Ausserdem kann ich so jetzt zum Beispiel auch gleich die Stringlänge zurückgeben und gleichzeitig negative Rückgabewerte für Fehlermeldungen verwenden.Dazu kommt, dass ich spätestens fürs Invertieren der char-Reihenfolge eh einen String an eine Funktion hätte übergeben müssen.
Oder wäre das auch ohne globale Variabeln anders gegangen?DirkB schrieb:
Übertreibst du da nicht etwas für den Anfang?
Nimm ein char-Array mit genug Platz und lese den String mit scanf ein.
Meinetwegen auch mit gets (danach aber nie wieder).Na ja, vielleicht ein bisschen übertrieben.
Aber ich muss's ja so oder so bald können, also kann's nicht schaden...
Jetzt weiss ich zumindest, wie ich bei Eingaben unbekannter Länge vorgehen kann (und das eine oder andere über Pointer und Strings in C), und wenn ich's nicht vergess, war's das wert.
-
Eine einfache Stringfunktion mit Doppelzeiger ist nicht nötig.
Der Prototyp sollte so aussehen:char * reverseStr(char *text);
Der Rückgabewert ist der Zeiger auf den String (also text)
Dann kannst du z.B. folgendes machen:printf("%s", reverseChar(str));
Das c in der while-schleife ist unnötig.
-
DirkB schrieb:
Eine einfache Stringfunktion mit Doppelzeiger ist nicht nötig.
Der Prototyp sollte so aussehen:char * reverseStr(char *text);
Der Rückgabewert ist der Zeiger auf den String (also text)
Dann kannst du z.B. folgendes machen:printf("%s", reverseChar(str));
Hm ...
Magst du vielleicht noch ein, zwei Worte zur Erzeugung des Rückgabestrings verlieren?
Denn wenn ich das so versuche, reklamiert er, ich gäbe die Adresse einer automatischen Variabel zurück, und diese wird ja bei Methodentermination verschrottet.Das c in der while-schleife ist unnötig.
Danke, war mir nicht aufgefallen.
Edit:
Und ich merke gerade, anstatt it hätt ich auch gleich j benutzen können.
-
User1291 schrieb:
Magst du vielleicht noch ein, zwei Worte zur Erzeugung des Rückgabestrings verlieren?
Denn wenn ich das so versuche, reklamiert er, ich gäbe die Adresse einer automatischen Variabel zurück, und diese wird ja bei Methodentermination verschrottet.Du sollst nicht die Adresse von dem Zeiger zurück geben (das wäre dann ja ein Doppelzeiger) sondern den Zeiger auf den Anfang von deinem Text. Das wäre dann ganz einfach
char * reverseStr(char *text) { // Die Variable text (also der Zeiger) darf hier nicht verändert werden. // Der Inhalt, auf den text zeigt schon. return text; }
-
DirkB schrieb:
User1291 schrieb:
Magst du vielleicht noch ein, zwei Worte zur Erzeugung des Rückgabestrings verlieren?
Denn wenn ich das so versuche, reklamiert er, ich gäbe die Adresse einer automatischen Variabel zurück, und diese wird ja bei Methodentermination verschrottet.Du sollst nicht die Adresse von dem Zeiger zurück geben (das wäre dann ja ein Doppelzeiger) sondern den Zeiger auf den Anfang von deinem Text. Das wäre dann ganz einfach
char * reverseStr(char *text) { // Die Variable text (also der Zeiger) darf hier nicht verändert werden. // Der Inhalt, auf den text zeigt schon. return text; }
Das Problem war eher sowas :
char * reverseStr(char **text) { //finde Grösse von text char* rtn = malloc(...); //Lese text rückwärts in rtn ein return rtn; }
Und er reklamiert, rtn sei automatisch, ich könne den Zeiger nicht zurückgeben (bzw sollte nicht).
-
User1291 schrieb:
Das Problem war eher sowas :
char * reverseStr(char **text) { //finde Grösse von text char* rtn = malloc(...); //Lese text rückwärts in rtn ein return rtn; }
Und er reklamiert, rtn sei automatisch, ich könne den Zeiger nicht zurückgeben (bzw sollte nicht).
Hast du da kein Zeichen vergessen? Denn das ist eigentlich ok.
Die Meldung tritt dann auf, wenn du die Adresse von einer lokalen Variablen zurück gibst.
Alsochar * reverseStr(char *text) { char rtn[] = "Hallo Welt!"; // lokales Array return rtn; // Rückgabe ist die Adresse von dem Array } // oder char * reverseStr(char *text) { char rtn; return &rtn; // Rückgabe ist die Adresse von der Variablen }
Und lass den Doppelzeiger (für text) weg
Der ist unnötig!
Wenn du das nicht schaffst, hast du Pointer (mit Arrays) nicht begriffen.
-
Werd mir das nochmals anschauen, danke.
Und lass den Doppelzeiger (für text) weg
Der ist unnötig!Der ist da, weil ich den Funktionsaufruf noch nicht entsprechend abgeändert hab (werd ich nachholen, sobald ich Zugriff auf den Code hab).