char [] - Gültigkeitsbereich
-
Sorry, wenn ich euch mit meinen Fragen zu C-Strings auf den Wecker gehe, aber ich will es genau wissen. Also, ich habe (grob) folgende Funktion:
char * make_adr ( irgendwelche Params) { char ss[250]; // ss wird nun entsprechend den Params mit Sinnvollem gefüllt return (ss); }
Zurückgegeben wird also ein Zeiger auf das char-Array, und ich kann anschließend was damit anfangen. Auch wenn ich die Funktion mehrfach aufrufe, kann ich die Ergebnisse dauerhaft verwenden, wenn ich sie in verschiedenen Variablen speichere. Aber irgendwie passt das nicht zu meinem Verständnis von lokalen Variablen. Ich dachte, die würden beim Verlassen der Funktion wieder freigegeben. Wo denke ich falsch?
Das zweite: Bei jedem Aufruf erhält ss eine neue Adresse. Wenn ich diese Funktion nun tausende mal aufrufe und die Inhalte von ss erhalten bleiben, wird der Speicher ja ganz schön zugestopft. Oder?
Gruß Reinhard
-
erin schrieb:
Auch wenn ich die Funktion mehrfach aufrufe, kann ich die Ergebnisse dauerhaft verwenden, wenn ich sie in verschiedenen Variablen speichere.
Was verstehst du hier unter "speichern"?
char *foo = make_adr(...); // oder char foo[250]; memcpy(foo, make_adr(...), sizeof(foo));
Also entweder "speichern" im Sinne von Zeiger auf das lokale Array oder im Sinne von kopieren des Inhalts des lokalen Arrays?
erin schrieb:
Aber irgendwie passt das nicht zu meinem Verständnis von lokalen Variablen. Ich dachte, die würden beim Verlassen der Funktion wieder freigegeben.
lokale Variablen vom typ auto werden auch wieder freigegeben. Das heisst aber nicht zwangsläufig, dass der Inhalt jener aber sofort wieder überschrieben wird.
Ansonsten wäre auch ein Codebeispiel (minimiert aber mit dem Effekt) interessant.
-
Ok, etwas Code, minimiert bis zur totalen Unsinnigkeit:
char *get_adr (char *name) { char ss[48]; strcpy (ss, name); return (ss); } int main () { char *a; char *b; a = get_adr ("Alter Sack"); b = get_adr ("Meine Orchidee"); puts (a); // Anzeige: Alter Sack puts (b); // Anzeige: Meine Orchidee puts (a); // Anzeige: Alter Sack }
Ich denke, dass deine Antwort auf die zweite Frage ziemlich aufschlussreich ist. Das Programm hat noch keine Verwendung für den freigegebenen Speicher und täuscht vor, die Zeiger seien noch gültig. Nicht ohne Tücken.
Aber da tauchen noch einige Anschlussfragen auf:
1. Was ist, wenn ich kein char-Array verwende, sondern einen Zeiger, dem ich mit malloc das nötige Hinderland verschaffe:
char *ss; ss = malloc (...); ... return (ss);
Bleibt nun der Speicher (nicht der Zeiger) erhalten, wenn ich ihn nicht in der Funktion mit free freigebe? Oder gehört auch der Speicher zu den lokalen Ressourcen, die am Funktionsende freigegeben werden?
2. Wenn in der Funktion kein free aufgerufen wird, kann das außerhalb mit der Variablen, die den Zeiger aufnimmt, geschehen? Also:
a = get_adr (...); free (a); // mit der Absicht, den Speicher von ss zu freizugeben
3. Von Pascal bin ich gewohnt, dass spätestens vor Beendigung des Programms (insbesondere auch in den Exception-Routinen) alle Speicherressourcen freigegeben werden müssen. Muss ich auch in einem C-Programm am Schluss alle noch offenen malloc-Variablen einsammeln und entsorgen?
-
Also ich würd das (ss) schon vor deiner Unterfunktion existieren lassen und ausreichend dimensionieren und dann in deiner Unterfunktion den Inhalt mit copy auffüllen.
-
erin schrieb:
Ok, etwas Code, minimiert bis zur totalen Unsinnigkeit:
char *get_adr (char *name) { char ss[48]; strcpy (ss, name); return (ss); } int main () { char *a; char *b; a = get_adr ("Alter Sack"); b = get_adr ("Meine Orchidee"); puts (a); // Anzeige: Alter Sack puts (b); // Anzeige: Meine Orchidee puts (a); // Anzeige: Alter Sack }
O.K. das sollte eigentlich nicht funktionieren. Welcher Compiler ist das und ist die Optimierung sehr hoch eingestellt? Ich glaube nämlich, dass der Compiler bei dir agressive Optimierungen durchführt, weshalb der Fehlerfall bei dir nicht auftritt.
erin schrieb:
Aber da tauchen noch einige Anschlussfragen auf:
1. Was ist, wenn ich kein char-Array verwende, sondern einen Zeiger, dem ich mit malloc das nötige Hinderland verschaffe:
char *ss; ss = malloc (...); ... return (ss);
Bleibt nun der Speicher (nicht der Zeiger) erhalten, wenn ich ihn nicht in der Funktion mit free freigebe? Oder gehört auch der Speicher zu den lokalen Ressourcen, die am Funktionsende freigegeben werden?
2. Wenn in der Funktion kein free aufgerufen wird, kann das außerhalb mit der Variablen, die den Zeiger aufnimmt, geschehen? Also:
a = get_adr (...); free (a); // mit der Absicht, den Speicher von ss zu freizugeben
3. Von Pascal bin ich gewohnt, dass spätestens vor Beendigung des Programms (insbesondere auch in den Exception-Routinen) alle Speicherressourcen freigegeben werden müssen. Muss ich auch in einem C-Programm am Schluss alle noch offenen malloc-Variablen einsammeln und entsorgen?
1. Ja
2. Ja
3. Speicher sollte prinzipiell dann freigegeben werden, wenn er nicht mehr benötigt wird. Es sit zwar so, dass moderne Betriebsysteme Speicher von foo aufräumen, sobald foo beendet ist, aber trotzdem sollte man selbst aufräumen.
-
TactX schrieb:
O.K. das sollte eigentlich nicht funktionieren. Welcher Compiler ist das und ist die Optimierung sehr hoch eingestellt? Ich glaube nämlich, dass der Compiler bei dir agressive Optimierungen durchführt, weshalb der Fehlerfall bei dir nicht auftritt.
gcc 3.3. Als C-Flag ist nur -Wall eingeschaltet. Keine Warnungen
-
Hugo Bin schrieb:
Also ich würd das (ss) schon vor deiner Unterfunktion existieren lassen und ausreichend dimensionieren und dann in deiner Unterfunktion den Inhalt mit copy auffüllen.
Sicher, das ist ein Weg, bei dem man alles im Griff hat. Andererseits möchte man bei einer Funktion, die oft und in verschiedenen Situationen eingesetzt wird, auch den Verwaltungskram dort erledigen lassen, angefangen von der Parameter-Überprüfung bis eben zur Bereitstellung von Speicher.
Ich habe mir daraufhin einmal bewusster die Prototypen in string.h angeschaut. Wenn ich nichts übersehen habe, arbeiten die tatsächlich alle in vorher bereit gestellten Speicherbereichen. Einige (z.B. strcat ) liefern zwar einen Zeiger zurück, aber der ist identisch mit dem übergebenen Zeiger auf den Zielbereich. Das bekräftigt deinen Vorschlag.
Reinhard
-
erin schrieb:
TactX schrieb:
O.K. das sollte eigentlich nicht funktionieren. Welcher Compiler ist das und ist die Optimierung sehr hoch eingestellt? Ich glaube nämlich, dass der Compiler bei dir agressive Optimierungen durchführt, weshalb der Fehlerfall bei dir nicht auftritt.
gcc 3.3. Als C-Flag ist nur -Wall eingeschaltet. Keine Warnungen
Das kann ich mit meinem gcc so nicht nachvollziehen. Die Warnung warning: function returns address of local variable müsste bei dir eigentlich auch kommen. Das Verhalten, dass die Strings "wie gewollt" erscheinen, kann ich nur mit -O3 erreichen. Aber eigentlich ist es auch total egal was rauskommt. Es ist "undefined behaviour", da kann alles passieren. Vom "korrekten" Ergebnis über einen Crash, bis hin zum Zusammenbruch der Kausalität.
-
TactX schrieb:
[...] bis hin zum Zusammenbruch der Kausalität.
Du meinst, wenn solcher Code jemals einen Entwicklerschreibtisch verlassen sollte, fangen Schweine an zu fliegen... *lol*
*scnr*
@OP: Was willst Du eigentlich damit erreichen?
greetz, Swordfish