Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » free

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
14.09.2003, 18:22 Uhr
Pablo
Supertux
(Operator)


Wie muss man folgendes am besten machen?


C++:
char* egalwas()
{
      static char x[5];
      // hier irgendwas mit x machen
     return x;
}



oder

C++:
char* egalwas()
{
      char* x;
      x = (char*)malloc(5);
      // hier irgendwas mit x machen
     return x;
}



Wenn ich die zweite Möglichkeit nehmen, wie kann ich den Speicher freigeben?

C++:
char* was = egalwas();
free(was);



Was passiert in diesem Fall mit free(was) ? Wird der Speicher, der von x in egalwas allokiert wurde, freigegeben? Muss man immer in diesem Fall eine Variable zuweisen? Weil wenn ich printf("%s", egalwas()); eingebe, hätte ich dann keine Möglichkeit den Speicher freizugeben.

Wie seht denn aus, wenn ich die erste egalwas() Funktion nehme?
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
14.09.2003, 18:52 Uhr
virtual
Sexiest Bit alive
(Operator)


Wesentliche Teile Deiner Frage werden in der FAQ beantwortet.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
15.09.2003, 12:18 Uhr
RHBaum



Und selbst fuer C ists "schlechtes" design !

1. bau keine funktionen die speicherbereich allokieren und ned wieder freigeben ...
2. wenn es doch tust, dann schreib die funktion so, das der User wenigstens informiert wird, das hier was "Ungewoehliches" getan wird ...


meiner meinung der beste weg:

C++:
int egalwas(char * buffer, int buffersize)
{
          // hier irgendwas mit x machen
    return errorcode; // irgendwie nen Fehlerwert zurueckgeben !
}




C++:
char * x = (char*)malloc(5);
int result = egalwas(x,5);

// ich hab hier erzeugt, also loesche ich hier!!! auch
free(x);



ist doch fuer den Benutzer viel uebersichtlicher ! und er weiss eher was er tun muss.

WIllst du aber das erzeugen von Variablen in ne Funktion packen, weils zu kompliziert ist ... dann nimm zeiger auf Zeiger !


C++:
int erzeugewas (char ** ppValue)
{
    // irgendwie sicherstellen, das dein zeigerZeiger ned schon auf was allokiertes zeigt !!!
    _ASSERT(*ppValue == NULL);

    *ppValue = (char*)malloc(5);
    // fehlercode irgendwie zurueckgeben ...
    // koennt ja sein das kein speicher frei war ...etc. !
    return errorcode;
}




C++:
char * x = NULL;
int result = erzeugewas(&x);

// hier wieder loeschen
free(x);



Ist ned so uebersichtlich wie vorher, aber zumindest sollte Name der Funktion und ZeigerZeiger als parameter den user erstmal aufmerksam machen, das da was erzeugt wird, was er wieder iergendwie freigeben sollte !

Ciao

Dieser Post wurde am 15.09.2003 um 12:19 Uhr von RHBaum editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
15.09.2003, 12:36 Uhr
0xdeadbeef
Gott
(Operator)


Diese _ASSERT-Konstruktion ist weder ANSI noch sonst irgendwie sinnvoll. ppValue wird ja nicht initialisiert, also kann es irgendwohin zeigen, und da kann irgendwas stehen. Dann hast du kein errorcode initialisiert, d.h. wenn überhaupt kannst du errno zurückgeben. Aber warum denn, das ist ja ne Thread-globale Variable. Außerdem sehe ich keinen Sinn darin, ein malloc in eine Funktion zu kapseln. Bei mehreren kann das sinnvoll sein, z.B. wenn du eine Matrix dynamisch alloziieren willst, aber so...

Die gängige Verfahrensweise wäre einen buffer entgegenzunehmen und auch zurückzugeben. Etwa so:

C++:
char *fill(char *buf, int len, char cnt) {
  int i;

  buf[len] = 0;
  for(i = 0; i < len; ++i) buf[i] = cnt;

  return buf;
}

/*...*/

char buffer[20];
printf("%s\n", fill(buf, 19, 'A'));


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
15.09.2003, 12:44 Uhr
virtual
Sexiest Bit alive
(Operator)


Ich denke, RHBaum meinte mit seinem assert

C++:
assert(*ppoValue==NULL);


was durchaus sinnvoll sein kann, um zu verhindern, daß ggf. bereits allokierter Speicher vergessen wird. Allerdings stimme ich dem nur begrenzt zu. Konsequenterweise sollte es erstens dann heissen

C++:
assert(ppoValue!=NULL && *ppoValue==NULL);


Um auf der sicheren Seite zu sein und zweitens wäre die Benutzung der Funktion der reinste Graus, weil man jedesmal den Pointer vor Aufruf der Funktion mit NULL initialisieren müsste, ohne daß man eine nenenswerte höhre Sicherheit vor Speicherlecks haben würden.
--edit: Fighting meine Rightschreibbugs
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 15.09.2003 um 12:48 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
15.09.2003, 13:10 Uhr
Pablo
Supertux
(Operator)


Danke für die Antwort. Die Lösung von @RHBaum mit dem int egalwas(char*,int); gefällt mir, aber trotzdem wollte ich wissen, wie char* Funktionen damit umgehen, und welche die beste Lösung wäre.

Die Funktion die ich mache, ist eine dec2bin (decimal to binary) und wandelt ein long in char um. Und die Funktion werde ich sehr oft in meinem Programm benutzen und deshalb wollte ich char* löschen, die ich nicht mehr brauche, damit sie nicht frei im Speicher bleiben.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
15.09.2003, 13:58 Uhr
RHBaum




Zitat:

Diese _ASSERT-Konstruktion ist weder ANSI noch sonst irgendwie sinnvoll.


Aua, das trifft mich hart

1. ok, _ASSERT ist M$ Schmutz, Asche auf mein haupt ! Aber ihr habt verstanden um was es ging ...


Zitat:

ohne daß man eine nenenswerte höhre Sicherheit vor Speicherlecks haben würden.


2. Aehm, mein Informatik Lehrer wuerde sich im Grab umdrehn ! Du deklarierst und definierst ne Variable, und gibst sie uninitialisiert an ne andere Funktion weiter ???
Ich haette mit dem Rohrstock auf die Finger bekommen .... aehm achnee, den gabs damals ja schon lange nicht mehr ! :-)
Ich mein wenn man ne Variable im eignen scope nicht gleich initialisiert, aber nur da verwende, ist es ja ok, aber bevor ich mit der Variable den scope verlasse .... dann initiialisier ich sie doch lieber gleich ! klar ists mehr aufwand, aber aufwand der sich auch lohnt, find ich !


Zitat:

Außerdem sehe ich keinen Sinn darin, ein malloc in eine Funktion zu kapseln



Zitat:

Dann hast du kein errorcode initialisiert


Ja und Ja
Nein, das malloc zu kapseln macht kein sinn in dem Fall, sollt ja nur nen Beispiel sein wie man es machen wuerd wenn mans braucht.
Nein, ich habe errorcode nicht initialisiert, sollte auch kein lauffaehiger code sein, sondern nur ne Anregung zum wie !

Also mir ging es definitiv nicht um den nachgefragten Fall zu loesen, sondern zu zeigen wie man es Prinzipiell machen sollte, meiner Meinung nach wie ichs mal gelernt hab !


C++:
char *fill(char *buf, int len, char cnt)
// rest ...


ob man den buffer selbst, oder nen explizieten Fehlercode zurueckgibt, haengt sehr mit dem Bedarf an der Fehlerinformation, und dem Context, in dem man die funktion braucht, zusammen. Den buffer zurueckgeben macht sinn, wenn man funktionsaufrufe schachteln will. Da bool ja auf Zeiger "matcht", ists fuer ne simple Fehlerabfrage auch ok ... Aber meist ignoriert mans sowieso und fragt den alten buffer doch auf null ab ?
Ich hab aber mal gelernt, das man zeiger auf komplexe strukturen als Rueckgabeparamter eigentlich meiden sollte. (vielleicht ist das schon ueberholt ? )
Ja ich weiss, die stdlib machts auch ... Ich denke mal ist dann eher geschmackssache, ich benutz es weniger ... ok, ich benutz auch mehr C++

Ciao ...

Dieser Post wurde am 15.09.2003 um 14:01 Uhr von RHBaum editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
15.09.2003, 14:05 Uhr
0xdeadbeef
Gott
(Operator)



Zitat:
RHBaum postete
Aehm, mein Informatik Lehrer wuerde sich im Grab umdrehn ! Du deklarierst und definierst ne Variable, und gibst sie uninitialisiert an ne andere Funktion weiter ???
Ich haette mit dem Rohrstock auf die Finger bekommen .... aehm achnee, den gabs damals ja schon lange nicht mehr ! :-)


Initialisieren kostet Rechenzeit, und die Variable wird nie ausgelesen. Welchen Sinn hätte es, die Variable zu initialisieren?



Zitat:
RHBaum postete
ob man den buffer selbst, oder nen explizieten Fehlercode zurueckgibt, haengt sehr mit dem Bedarf an der Fehlerinformation, und dem Context, in dem man die funktion braucht, zusammen.


Wofür gibt es denn errno? Null zurückgeben, um anzuzeigen, dass ein Fehler aufgetreten ist, errno setzen. Meistens setzen die Funktionen der stdlib errno schon selbst.


Zitat:
RHBaum postete
Ich hab aber mal gelernt, das man zeiger auf komplexe strukturen als Rueckgabeparamter eigentlich meiden sollte. (vielleicht ist das schon ueberholt ? )

Ein char ist für mich nicht gerade eine komplexe Struktur. Und abgesehen davon sehe ich auch nichts verwerfliches daran, einen Zeiger auf eine Struktur zurückzugeben. Zeiger auf gemallocte Speicherbereiche zurückzugeben ist in aller Regel unschön, aber das ist ja auch was völlig anderes.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 15.09.2003 um 14:06 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
15.09.2003, 14:18 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
RHBaum postete
[quote]
2. Aehm, mein Informatik Lehrer wuerde sich im Grab umdrehn ! Du deklarierst und definierst ne Variable, und gibst sie uninitialisiert an ne andere Funktion weiter ???


zB wird bei scanf keiner der Empfangsparameter großartig initialisiert (es ist sache des Aufrufers anhand des Returncodes von scanf richtig zu reagieren). Eine Forderung, daß der Aufrufer die Parameter irgendwie in solchen Situationen vorinitialisieren müsste, ist in meinen Augen auch ziemlicher Quatsch: Wenn die von Dir geschriebene Funktion einen Fehler macht, sollte sie - falls es zu unsicher ist, dies allein über einen entsprechenden Returncode zu signalisieren - ppoValue (oder wie die Varaible auch immer hieß) von sich aus auf NULL setzen. Alles andere wäre nichts anderes als versteckte redundanz.
edit:
Ich denke, man muß halt unterscheiden, zwischen Input, Output und Input/Outputparmetern. Im Diskutierten Fall ordne ich die Variable eindeutig der kategorie Outputparameter zu, woduch die Funktion für die Initialisierung zuständig ist.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 15.09.2003 um 14:20 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
15.09.2003, 14:46 Uhr
RHBaum




Zitat:

Welchen Sinn hätte es, die Variable zu initialisieren?


Wie gesagt, Sicherheit, speicherbereiche ... ich geh davon aus, als Autor der Funktion, das die User ned immer wissen sie tun ! Man vergisst grade bei funktionen die Speicher allocieren, den speicher auch wieder freizugeben. Meist verwendet man das auch noch in ner schleife mit der selben variable ... das schuetzt zumindest etwas davor ! Wie gesagt, spaetestens in diesem Fall macht sich der Anwender nen Kopf, warum es so ist ...
Wie ging der Satz mit Paranoia und dem Preis ???


Zitat:

Wofür gibt es denn errno?


Erzeugst du fuer die Anwendungs logischen Sachen immer eigene Fehlercodes ? "Konnte Vornamen nicht erzeugen weil Nachname nicht angegeben!" ... sowas fang ich lieber mit eignen Codes ab ... Doof steht der benutzer da, wenn buffer = NULL und erno auch null ist ...
Wenn du davon ausgehst, das der buffer immer erzeugt werden soll, und wenn mal nicht, sowieso nen schwerwiegendes problem vorliegt, dann ok !
Fehlercode ist sicher auch der falsche Ausdruck, eher Statuscode in dem Fall ...
Fehlerbehandlung in C ist auch ned so mein Fall, ich mag lieber exceptions !


Zitat:

Ein char ist für mich nicht gerade eine komplexe Struktur.


nicht wirklich ... trotzdem ists gewaltig, was hinter nem char stecken kann.
Ich bevorzuge lieber flache typen, also speziell int, sonst auch float, double ... und prinzipiell weniger Zeiger, die pack ich lieber in die Parameterliste ... wobei nen Zeiger auch ned Wirklich komplex ist !

Die Zeiten aendern sich. Ich denk mal auch der Umgang mit C. Fuer "komplexe" programme nimmt heut keiner mehr C ! Nur noch fuer sachen, wo es wirklich auf codegroesse und Laufzeit ankommt. Von der Warte hasst Du sicher recht !

Ciao ...

Dieser Post wurde am 15.09.2003 um 14:47 Uhr von RHBaum editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: