Ziel ist es, einen bestimmten Bereich in einem String zu kopieren.
Definiert wird dabei der Startoffset vom übergebenen String und ein
EndZeichen!
Meine Frage bezieht sich nun auf den return Befehl.
1
returnpTempString;
Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale
Variable zurückgebe?
Irgendwie erscheint mir dies als nicht möglich.
Falls nein, gibt es einen elegante Lösung, zur vermeidung von diversen
globalen Variablen?
Danke schonmal!
Kein Name schrieb:> Warum willst du es anders machen?
Möchte ich nicht :) Hab nur den Wald vor lauter Bäumen nicht gesehen...
Ist wohl das beste!
Danke
Claudio Hediger schrieb:>> Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale> Variable zurückgebe?
A) Lokale Variablen existieren nach dem Funktionsaufruf nicht mehr
B) Du willst doch den Zielbuffer ausserhalb der Funktion benutzen, also
definiere ihn doch dort und übergebe einen ZielZeiger
pTempString zeigt auf TempString, sprich einer lokalen Variablen auf dem
Stack der nach Aufruf der Funktion nicht mehr gültig ist. Also wie Du
schon vermutet hast nicht zulässig.
Der Witz daran: Es hat gute Chancen in der aufrufenden Funktion u.U. zu
funktionieren, da der Stack sehr wahrscheinlich noch nicht überschrieben
wurde. Kann also sein, dass der Fehler erst mal nicht auffällt.
TempString kann maximal 20 Zeichen fassen, SearchIn hat vielleicht mehr.
Das könnte den Stack ruinieren und ein Angriffsziel darstellen bzw einen
Absturz verursachen.
Es geht, du musst aber deinen Stringbuffer als static declarieren.
Weiters hast du einen Denkfehler, du lieferst den Pointer auf das
Stringende zurück.
Normalerweise macht man dies so:
foo(char*str,char c, int offset) {
static char buff[500]; // als beispiel
int i=0;
if(str&&offset<strlen(str))
for(str+=offset;*str&&*str!=c&&i<sizeof(buff)/sizeof(buff[0]);)
buff[i++]=*str++;
buff[i]='\0';
return buff;
}
Cube_S schrieb:> TempString kann maximal 20 Zeichen fassen, SearchIn hat vielleicht mehr.> Das könnte den Stack ruinieren und ein Angriffsziel darstellen bzw einen> Absturz verursachen.
Vielen Dank für diesen Hinweis :)
LOL schrieb:> 1.)> SearchIn=blablubb> from=100>> Was passiert bei: SearchIn += from; //Offset definieren!
Dann stürzt das Teil ab!
Soll ich also noch "> strlen(SearchIn)" machen?
LOL schrieb:> 2.)> Änderst du "from", "until_sign" und ggf. *SeachIn?char> *copy_from_until(unsigned char from, char until_sign, char *SearchIn)>> Wenn nicht, sollten die vermutlich const sein.
Vielen Dank für diesen Hinweis!
Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann
man const macht und wann nicht. Und was es für vorteile hat.
Bezieht sich dein "änderst du nochmals" lediglich auf die Funktion?
Also ob ich from und until innerhalb der funktion ändere?
Wenn dies die Frage war, dann nein.
Claudio Hediger schrieb:> Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale> Variable zurückgebe?
Zulässig ist es.
> Irgendwie erscheint mir dies als nicht möglich.
Möglich ist es, da es zulässig ist. Sinnvoll ist es nicht. Das ist halt
C, wie es leibt und lebt.
> Falls nein, gibt es einen elegante Lösung, zur vermeidung von diversen> globalen Variablen?
Ja. Der Caller übergibt eine Referenz auf einen ihm gehörenden
Speicherbereich, in dem der Callee die Auschnittskopie zurückgibt.
Natürlich nur dann, wenn der Platz dort dafür reicht. Außer der
Speicherreferenz muß also auch die Größe des referenzierten
Speicherbereichs übergeben werden und der Callee muß verschiedene
Situationen zurückmelden können, als da wären:
Fehler:
Nullreferenz Quelle
Nullreferenz Ziel
Ungenügender Speicher im Ziel (komfortabler: soundsoviel Zeichen
benötigt)
Gut.
oder:
Besser: soundsoviel Zeichen im Ziel
Programmierst du den ersten Tag in dieser Drecks-Sprache?
Und i<sizeof(buff)/sizeof(buff[0]) sollte
1+i<sizeof(buff)/sizeof(buff[0]) sein, ich mache dies meistens mit
Konstanten arbeite, z.B. LINE_LEN und dann bei der Deklaration einfach
buff[LINE_LEN+1] ,
> Dann stürzt das Teil ab!> Soll ich also noch "> strlen(SearchIn)" machen?
Oder halt einfach und ineffizient den *char komplett in der Schleife
zeichenweise durchgehen und abbrechen wenn \0 kommt.
Wenn du mehr Durchläufe als "from" hast, fängst du an zu verlgeichen,
wenn du mehr als from+20 Durchläufe hast, brichst du ab (-> Cube_S).
Die Sache mit dem "const" im Funktionskopf ist eher "hübsch", damit wird
jedem der die Funktion sieht klar, dass du diese Variablen nicht
änderst, im Gegensatz halt zu den Rückgabevariablen/Pointern/Referenzen
wie auch immer man das gerade nennen mag.
Claudio Hediger schrieb:> Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann> man const macht und wann nicht. Und was es für vorteile hat.
Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte
sind "call by value" und werden in der aufrufenden Funktion nicht
verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur
die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten
auf das "const"
Cube_S schrieb:> Claudio Hediger schrieb:>> Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann>> man const macht und wann nicht. Und was es für vorteile hat.>> Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte> sind "call by value" und werden in der aufrufenden Funktion nicht> verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur> die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten> auf das "const"
Achsoo...
Na dann habe ich ja bisher nichts verpasst :)
Danke für die Erklärung!
Nur der Vollständigkeit halber - hier schrieb ich offensichtlichen
Blödsinn:
> wenn du mehr als from+20 Durchläufe hast
Das sollten 20 gültige weitere Durchläufe nach dem Startzeichen/Offset
sein, wegen der Pufferlänge.
LOL schrieb:> Nur der Vollständigkeit halber - hier schrieb ich offensichtlichen> Blödsinn:>>> wenn du mehr als from+20 Durchläufe hast>> Das sollten 20 gültige weitere Durchläufe nach dem Startzeichen/Offset> sein, wegen der Pufferlänge.
Achsoo
Ok jetzt ergibt es mehr sinn :)
Cube_S schrieb:> Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte> sind "call by value" und werden in der aufrufenden Funktion nicht> verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur> die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten> auf das "const"
Das ist nicht richtig, zumindest nicht solange wir nicht wissen, wie die
consts gesetzt werden. Es gibt ein Unterschied zwischen
1
char*const// konstanter Pointer auf char
2
charconst*// Pointer auf konstanten char
3
charconst*const// konstanter Pointer auf konstanten char
Ein char const* macht auch bei call by value durchaus Sinn, da es
verhindert, dass ein durch den Pointer referenziertes Objekt verändert
wird. Allerdings bin ich mir nicht sicher, ab welchem C-Standard diese
Qualifier für den Compiler bindend sind. Bei ANSI-C heißt es noch:
„Except that it should diagnose explicit attempts to change a const
object, the compiler may ignore these qualifiers.“
Der Compiler sollte also warnen, muss es aber nicht. Spätestens bei C++
allerdings sind dies Qualifier binden.
ah8 schrieb:> Spätestens bei C++> allerdings sind dies Qualifier binden.
Alles in allem hast Du natürlich recht. Aber ich habe bei größeren
Projekten nicht erlebt, dass sich das "const" konsequent durchsetzen
lässt. Gerade bei C++ Klassen mit const Zeigern darauf. Man kommt immer
an einen Punkt wo das Objekt der Begierde zwar im Prinzip "const" sein
soll aber man doch irgend etwas unbedeutendes darin ändern will. Damit
tritt man oft eine nicht aufzuhaltende Lawine los.
C# und Java verzichten darauf. Ich denke nicht ganz zu unrecht.
Cube_S schrieb:> ah8 schrieb:>> Spätestens bei C++>> allerdings sind dies Qualifier binden.>> Alles in allem hast Du natürlich recht. Aber ich habe bei größeren> Projekten nicht erlebt, dass sich das "const" konsequent durchsetzen> lässt. Gerade bei C++ Klassen mit const Zeigern darauf. Man kommt immer> an einen Punkt wo das Objekt der Begierde zwar im Prinzip "const" sein> soll aber man doch irgend etwas unbedeutendes darin ändern will.
Dann machst du den Member 'mutable'