Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » FAQ C / C++ (ANSI-Standard) » malloc() & co

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 <
000
30.09.2003, 14:08 Uhr
HRI-Dummy



Wer kann mir mal bitte ganz ausfuehrlich (stellt Euch einfach vor, Ihr muestet es einem Kleinkind erklaeren) die Bedeutung, Syntax und Anwendung von malloc(), calloc(), etc. erklaeren.
Was ich besonders wissen moechte, wenn ich in C mit Zeigern arbeite, muss ich dann malloc verwenden, so wie in C++ new, oder gibt es einen (anfaengerverstaendlichen) Weg drumherum?
Ich versteh bisher echt nur Bahnhof, bitte nicht in Manual-Form schreiben.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
30.09.2003, 14:48 Uhr
0xdeadbeef
Gott
(Operator)


Au weia, das ist ziemlich kompliziert, aber ebenso wichtig. Ich versuchs mal zu erklären. Also, man unterscheidet im wesentlichen zwischen drei logischen Speicherbereichen - dem statischen, dem Stack und dem heap. Statisch alloziierte Daten stehen schon zur Compilezeit fest; darunter fallen globale Variablen, und solche die explizit als static deklariert wurden. Das sind im Grunde ja auch globale Variablen, die halt nicht von überall ansprechbar sind. Beispiel:

C++:
int globales_int_array[10]; /* <-- statisch */

int foo() {
  static int i = 0; /* <-- ebenfalls statisch. foo gibt zurück, wie oft foo bisher aufgerufen wurde */
  return ++i;
}


statische Daten sind einfach. Es steht schon zur Compilezeit fest, wieviel Speicher für sie benötigt wird, und sie sind immer vom Programmstart bis zum Programmende vorhanden. Deshalb werden sie idR gleich in die Executable reinkompiliert. Das zweite ist der Stack. Auf dem Stack liegen lokale Variablen, Parameter usw. Nachdem der Block, in dem sie deklariert wurden, verlassen wird, verlieren sie ihre Gültigkeit. Zum Beispiel:

C++:
void bar(int i) { /* <-- i liegt auf dem Stack */
  int j; /* <-- j liegt auf dem Stack */
  for(j = 0; j < 10; ++j)
  {
    int k = 0; /* <-- k liegt auf dem Stack */
  } /* <-- hier endet der Block, in dem k deklariert wurde. k verliert seine Gültigkeit */
  /* tu ein bisschen mehr*/
} /* Hier verlieren i und j ihre Gültigkeit */


Dadurch, dass die Variablen ihre Gültigkeit verlieren, gibt es einige Pitfalls, die man kennen sollte. Zum Beispiel ist es nicht möglich (Naja, schon möglich, aber du kannst dich nicht drauf verlassen, dass es den gewünschten Effekt hat), Zeiger auf lokale Variablen zurückzugeben. Zum Beispiel:

C++:
char *baz() {
  char ret[] = "Hello, World!"
  return ret;
} /* <-- hier verliert ret seine Gültigkeit. */

/* ... */
puts(baz()); /* <-- Der Rückgabewert von baz ist nicht definiert */


sowas sind beliebte Heisenbugs. Das dritte ist der Heap. Auf dem Heap kann man dynamisch Speicher anfordern, der für alles andere so lange gesperrt ist, bis er explizit wieder freigegeben wird. Da kommen malloc und calloc usw. ins Spiel. Zum Beispiel:

C++:
char *buf = malloc(sizeof(char) * 10); /* fordert 10 * sizeof(char) byte speicher an */
/*...*/
free(buf);


Damit kannst du dann auch Zeiger auf Speicherbereiche zurückgeben, z.B.:

C++:
char *qux() {
  char *ret = malloc(sizeof("Hello, World!"));
  strcpy(ret, "Hello, World!");
  return ret;
}

/*...*/
char *s = qux();
puts(s);
free(s); /* <-- hier fliegt der Speicher wieder vom Heap und kann neu vergeben werden*/


Das hat den Nachteil, dass du extrem vorsichtig sein musst, dass du deinen Speicher auch wieder freigibst. Wenn du in diesem Fall zum Beispiel schreibst:

C++:
puts(qux());


...was ziemlich verlockend ist, hast du keine Möglichkeit mehr, den Speicher wieder vom Heap zu schmeißen. Der ist dann weg (sowas nennt sich auch "Speicherleck"). Aus diesem Grund empfiehlt es sich nicht, Speicher in einer Funktion anzufordern und in einer anderen wieder freizugeben. Auf die Art ist es nur eine Frage der Zeit, bis du Speicher leckst. Ein gängiger Weg, solche Speicherlecks zu umgehen, ist Buffer mitzugeben, etwa so:

C++:
char *quux(char *buf) {
  strcpy(buf, "Hello, World!");
  return buf;
}

/*...*/
char buf[20];
puts(quux(buf));
/* keine Freigabe erforderlich - buf liegt auf dem Stack */


wenn man auch noch segfaults vermeiden will, gibt man die Länge des Buffers mit:

C++:
char *xyzzy(char *buf, size_t len) {
  if(len < sizeof("Hello, World!") / sizeof(char)) {
     /* Fehlerbehandlung - buffer nicht lang genug */
  } else {
    return quux(buf); /* quux siehe oben */
  }
}



Was die Syntax von malloc/calloc angeht - malloc fordert soviele byte speicher an, wie der Parameter es ihm sagt. (siehe oben). calloc könnte man schreiben als

C++:
void *calloc(size_t anzahl, size_t groesse) { return malloc(anzahl * groesse); }


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 30.09.2003 um 14:54 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
30.09.2003, 15:13 Uhr
ao

(Operator)



Zitat:
0xdeadbeef postete
calloc könnte man schreiben als

C++:
void *calloc(size_t anzahl, size_t groesse) { return malloc(anzahl * groesse); }



Beinahe. Ich stimme für

C++:
void *calloc(size_t anzahl, size_t groesse)
{
    void *p = malloc(anzahl * groesse);
    if (p == NULL) return NULL;

    memset (p, 0, anzahl * groesse);  /* calloc nullt den Speicher */
    return p;
}


Aber sonst: eine FAQ-reife Beschreibung, alle Achtung.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
30.09.2003, 16:19 Uhr
HRI-Dummy



So langsam wird die Sache klarer. Bis auf zwei Punkte, was ist foo????????
Und was macht die Funktion puts()?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
30.09.2003, 16:25 Uhr
typecast
aka loddab
(Operator)


Der Ausdruck Foo steht bei Erklärungen dafür, dass du hier deinen eigenen Namen (also Funktions, Variablennamen) einsetzten sollst. Foo wird gerne als Beispiel genommen.
Puts steht für PutString und gibt einfach einen String mit zeilenumbruch aus
--
All parts should go together without forcing. ... By all means, do not use a hammer. (IBM maintenance manual, 1925)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
30.09.2003, 16:28 Uhr
HRI-Dummy



Endlich mal Klartext, danke!
Diese foo Geschichte ist mir schon so oft ueber den Weg gelaufen, ich konnte nur in keinem Manual was dazu finden, jetzt verstehe ich auch warum...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
30.09.2003, 17:08 Uhr
0xdeadbeef
Gott
(Operator)


Wenn dus ganz genau wissen willst: www.catb.org/jargon/html/F/foo.html - da sind dann auch gleich bar, baz, qux, quux, xyzzy usw. erklärt.

--edit: Ich denke, der Thread ist tot, und weil er einen gewissen Informationsgehalt hat, stecke ich ihn einfach mal in die FAQ.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 06.10.2003 um 12:01 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ FAQ 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: