Dynamische Speicherverwaltung mit malloc

wims_live

Grünschnabel
Hallo zusammen...

Als Anfänger treibt man sich ja (zwangsläufig) gern und viel in diversen Foren herum. Und als Anfänger in (C) bin ich hier bei euch in der schönen tutorials-community gelandet... Natürlich habe ich mich mit der Hoffnung registriert, hier Antworten auf meine Fragen zu erlangen... :-)

Ich befasse mich gerade mit der dynamischen Speicherverwaltung. Und dies im Zusammenhang mit einem kleinen Programm, welches in recht rudimentärer Art und Weise ein paar Mitarbeiter verwalten soll. (Eingabe, Ausgabe, Bearbeiten, Löschen, etc...)

Eine Bedingung ist diese, ich zitiere: "Für die Speicherung der Namen soll nur der unbedingt notwendige Speicherplatz verwendet werden."

Nun habe ich die die malloc-Anweisung so eingebaut, das ich einen Zeiger als Strukturvariable definiere. (In dieser Struktur wird auf eine weitere verwiesen, in welcher die pers. Daten des einzelnen Mitarbeiters stehen)

Anhand diesen Zeigers fordere ich über (malloc) Speicher für die Struktur an.

Diese Anforderung multiplizier ich mit der (Max_Anzahl) an Mitarbeiter.

Danach lädt er die Liste in die Struktur und es geht ganz normal weiter.

Doch das ist ja nicht unbedingt das, was gefordert ist, right? Die Speicheranforderung ist ja recht universell gehalten. Wie kann ich das jetzt nur auf den Namen bezogen realisieren?
Eine Liste mit den Mitarbeitern wird zu Beginn des Programmes geladen. Dann wird damit gearbeitet, und zum Programmende wird die Liste wieder in eine Datei geschrieben.

Hier mal die Strukturdefinitionen...
Code:
// Struktur der Inhalte / Daten für einen einzelnen Mitarbeiter (Typ)
struct mitarbeiter_daten
{
    int persnr;
    char nachname[30];
    float stundenlohn;
    float arbeitsstunden;
    float gesamtlohn;
};

// Struktur für alle Mitarbeiter
// bezieht sich auf die Struktur der Inhalte
// Zusätzlich eine Variable für die Anzahl der Mitarbeiter
struct mitarbeiter_db
{
    struct mitarbeiter_daten mitarbeiter[ANZ_MITARBEITER];
    int anzahl;
};

Und hier meine Definition für die malloc-Anweisung
Code:
// MALLOC
    // Fordert laut meinem Verständnis Speicher in der Größe der Struktur an
    // Multipliziert mit der maximalen Anzahl an Mitarbeitern
    struct mitarbeiter_db *speicher;
    if ((speicher = malloc(ANZ_MITARBEITER * sizeof(struct mitarbeiter_db))) != 0 )
    {

    }
    else
    {
        // Fehlerroutine
        printf("%s\n", FEHLER_SPEICHER);
    }

Wenn ich das richtig verstanden habe, dann muss ich doch die Größenangabe im char-Array für die Nachnamen ([30]) herausbekommen, oder?
Wenn einer z.B. Meier heißt, dann hat er ja bloß 5 Buchstaben, dann noch das '\0' und er wäre fertig, oder? Es könnte aber auch einer "Bartholdy-Mendelssohn" heißen, dann wäre der Bedarf ungleich höher...

Hmm, wie ihr seht, plagt mich das etwas. Für einen oder zwei elegante Tipps wäre ich sehr dankbar. Die Tipps sollen als Diskussionsbasis dienen, und vor allem mein Verständnis bereichern. (Nichts geht über den guten alten AHA-Effekt :-) )

In diesem Sinne, besten Dank im voraus....

Gruß
 
Hi.
Hier mal die Strukturdefinitionen...
Code:
// Struktur der Inhalte / Daten für einen einzelnen Mitarbeiter (Typ)
struct mitarbeiter_daten
{
    int persnr;
    char nachname[30];
    float stundenlohn;
    float arbeitsstunden;
    float gesamtlohn;
};

// Struktur für alle Mitarbeiter
// bezieht sich auf die Struktur der Inhalte
// Zusätzlich eine Variable für die Anzahl der Mitarbeiter
struct mitarbeiter_db
{
    struct mitarbeiter_daten mitarbeiter[ANZ_MITARBEITER];
    int anzahl;
};

Und hier meine Definition für die malloc-Anweisung
Code:
// MALLOC
    // Fordert laut meinem Verständnis Speicher in der Größe der Struktur an
    // Multipliziert mit der maximalen Anzahl an Mitarbeitern
    struct mitarbeiter_db *speicher;
    if ((speicher = malloc(ANZ_MITARBEITER * sizeof(struct mitarbeiter_db))) != 0 )
Das ist so nicht richtig. Die Struktur mitarbeiter_db enthält ja bereits ANZ_MITARBEITER viele Mitarbeiter. Mit dieser Anweisung würdest du Speicher für ANZ_MITARBEITER * (sizeof(struct mitarbeiter_daten) * ANZ_MITARBEITER + sizeof(int)) Bytes anfordern... :-o

Es reicht:
C:
if ((speicher = malloc(sizeof(struct mitarbeiter_db))) != 0) ...
Wenn ich das richtig verstanden habe, dann muss ich doch die Größenangabe im char-Array für die Nachnamen ([30]) herausbekommen, oder?
Richtig. Da kannst du kein festes Array mehr verwenden, sondern einen Zeiger.

Je nachdem wieviel Speicher du für den Namen brauchst, allozierst du dann den Speicher und kopierst den Namen dort rein. Wenn du den Mitarbeiter entfernst, mußt du dann natürlich den Speicher wieder freigeben.

Gruß
 
Hi!

Wenn ich dein Problem richtig verstanden habe, willst du speicher dynamisch anlegen.
Meines Wissens allokierst du nicht den gesamten Speicher für alle Mitarbeiter, sondern einzeln zur Laufzeit des Haptprogramms main.

Du kannst somit eine verkettete Liste in C entwerfen, sodass du auch nur soviel Speicher allokiert, wie du auch nur brauchst.

Gehen wir mal davon aus ANZ_MITARBEITER ist durch 100 vordefiniert.
Was ist aber jetzt, wenn der 101ste Mitarbeiter eingetragen werden soll.
Dann musst du ja den define-Befehl wieder ändern....

Eine Möglichkeit in C zu arbeiten ist die Verkette Liste....

C:
struct mitarbeiter {
      int personalnummer;
      char nachname[30];
      float stundenlohn;
      float arbeitsstunden;
      float gesamtlohn;
      struct mitarbieter *next;
};

Wenn du dir diese Struktur ansiehst kannst du ganz leicht damit arbeiten.
um ein neues element zu erzeugen kannst z.B. so vorgehen.

C:
void neuesElement(int pnr,char* nn,float stdl,float workstd,float gsl,struct mitarbeiter *liste[])
{
   struct mitarbeiter *buff=NULL;

   buff = *liste;
   if (buff == NULL)
   {
      /* erstes Listenelement erzeugen */
      buff = (struct mitarbeiter *)malloc(sizeof(struct mitarbeiter));
      if(buff==NULL) {
            printf("\n\nFEHLER BEI SPEICHERALLOKIERUNG!\n");
            return;
      }
      *liste = buff;
   }
   else
   {
      /* weitere Listenelemente erzeugen */

      /* Das Ende der Liste suchen */
      while (buff->next != NULL) buff = buff->next;

      /* neues Listenelement erzeugen */

      buff->next = (struct mitarbeiter *)malloc(sizeof(struct mitarbeiter));
      if(buff==NULL) {
            printf("\n\nFEHLER BEI SPEICHERALLOKIERUNG!\n");
            return;
      }
      buff = buff->next;
   }
   buff->personalnummer = pnr;
   strcpy(buff->nachname, nn);
   buff->stundenlohn=stdl;
   buff->arbeitsstunden=workstd;
   buff->gesamtlohn=gsl;
   buff->next=NULL;
}

Das läuft alles so ab.........

Du übergibst der Funktion die einzelnen Daten des Mitarbeiters, und die Liste(muss vorher Deklariert werden).

Wenn die Liste leer ist, also noch kein Eintrag vorhanden ist, setz er das erste Listen element.
Wenn schon was in der Liste steht sucht er das Letzte Listenelement.
Dann greift er mit buff-> next auf das Element zu was angehängt wird.

Wie du siehst wird nur dann Speicher angelegt, wenn ein neuer Eintrag erfolgt.

Ich hoffe ich konnte helfen.......

mfg
Sfuccma
 
Zuletzt bearbeitet:
@sfuccma

Danke für deinen Ansatz. Die Datenstruktur der verketteten Liste ist äußerst interessant, jedoch will ich erstmal den Ansatz mit der Speicheranforderung (durch malloc) verfolgen.

@deepthroat

Hab deinen Ansatz verstanden und den Code diesbezüglich abgeändert:

Code:
// MALLOC
    // Fordert laut meinem Verständnis Speicher in der Größe der Struktur an

    // Vereinbarung einer Variablen bzgl. einer Struktur;
    struct mitarbeiter_db *liste;
    if ((liste = malloc(sizeof(struct mitarbeiter_db))) != 0)
    {
        // Funktionsaufruf zum Laden der Mitarbeiterdatei
        // Rückgabewert im Fehlerfall und Routine
        ausgabe = Datei_Laden(liste);
        if (ausgabe == 1)
        {
            return EXIT_FAILURE;
        }
    }
    else
    {
        // Fehlerroutine
        printf("%s\n", FEHLER_SPEICHER);
    }
Zum Verständnis:

Ich fordere nun Speicher an, in Größe der Struktur, um in meinem Fall, am Programmstart die Liste der Datei in das Programm zu laden. Wenn ich jetzt das starre Array für den Nachnamen in einen Zeiger umwandele, kann es doch einzig und allein damit nicht getan sein, oder? Denn das Programm kann ja noch nicht wissen, wie lang die Namen in der zu ladenen Datei sind.

Muss ich also nochmal ne extra Anforderung machen, bezogen auf den Namen? Bzw. ist die Vorgabe bzgl. des Speichers ja auf die Speicherung des Namens bezogen. Will meinen, das, wenn die Datenstruktur der Mitarbeiter wieder in die Datei geschrieben werden soll, muß die explizite Anforderung erfolgen?!

Also:

Untersuche ich jeden einzelnen Namen und fordere explizit Speicher an (und schreibe dann)? Wenn ja, gebe ich ihn dann wieder frei, um für den nächsten Namen den Vorgang erneut zu starten?

Hoffe, ich konnte mein Problem ausdrücken.

Das Grundproblem bzgl. der ressourcenschonenden Programmierung habe ich m.E. verstanden, jedoch erscheint mir die ganze Materie noch etwas zu aufwendig...

Danke schonmal für die Bemühungen,

Gruß

P.S. Wie kann ich die Codeansicht incl. Zeilennummern aktivieren?
 
Zuletzt bearbeitet:
Hallo nochmal

Du kannst den Speicher nicht wieder freigeben, für ein vorheriges Element, wenn du ein neues erzeugen willst. Du möchtest doch anscheinend später noch darauf zugreifen können oder?

Kann ja nicht gehen musst dir das so Vorstellen:

Du erzeugst ja ein Speicher von der Größe der Struktur, also für EIN Elmenet.
In dem Speicher deines Rechners wird somit Specher dafür angelegt und deine Liste zeigt auf diesen Speicher, sodass du über diese Liste darauf zugreifen kannst.
Der Speicher ist ja den du angelegt hast, irgendeine Adresse, die der Zeiger, also deine Liste zugewiesen bekommst.

Wenn du jetzt diesen Speicher wieder freigibst, kann es ja sein, das deine Mitarbeiterdaten wieder überschrieben werden.

Speicher wird erst unmittelbar vor Programmende wieder freigegeben.

Grundsätzlich ist es aber eigentlich so, dass die intelligente Maschine, oder besser Ihr Hersteller, veranlasst, dass nach Programmende Speicher automatisch freigegeben wird......Würd mich aber nicht drauf verlassen....

Wie du C Code schreiben willst?! Ist ganz einfach
anstatt " [ code ]....." schreibste " [ code=c ] ".

mfg
 
Zuletzt bearbeitet:
Morgen.

Da das Gesagte von sfuccma evtl. etwas unklar ist, formuliere ich es evtl. nochmal etwas anders:

Zuerst mußt du die mitarbeiter_db initialiseren. Dazu allozierst du Speicher und hast bereits ANZ_MITARBEITER mitarbeiter_daten Strukturen angelegt. Diese sind aber noch nicht richtig initialisiert und halten noch keine Daten.

In der mitarbeiter_db speicherst du ja sozusagen den Füllstand des mitarbeiter Arrays. Und der ist anfangs erstmal 0.

So weit so gut.

Wenn du nun einen Mitarbeiter hinzufügen willst mußt du erstmal sicherstellen das genug Platz ist (mitarbeiter_db also noch nicht voll ist).

Dann müßtest du die ganzen Daten des neuen Mitarbeiters abfragen. Den Namen liest du einfach in ein temporäres char-Array ein. Das kannst du mit fgets machen.

Wenn das Einlesen erfolgreich war, dann kannst du feststellen wie lang der Name ist, und Speicher für liste->mitarbeiter[liste->anzahl].nachname allozieren.

Den Namen kopierst du mit strcpy dann dort rein.

Das Speichern der Daten ist dann wieder etwas komplizierter. Jetzt kannst du nämlich nicht einfach mit fwrite die Struktur in die Datei schreiben, da würde ja nur ein Zeiger drin stehen - der bei einem Neustart des Programms nicht mehr gültig ist.

Gruß
 
Hallo zusammen,

vielen Dank für die kompetente Hilfe.

Ich habe mein Problem, dank den konstruktiven Denkanstößen gelöst bekommen.

Ich habe es so gelöst, das ich (obwohl nicht zwingend vorgeschrieben) zum Programmstart Speicher für die gesamte Struktur anfordere. Im Einzelfall, wenn dann die Namen eingelesen werden, habe ich dies über ein temp. Array gelöst, und dann explizit im einzelnen Speicher in Länge der Namen (+ '\0') angefordert. Nach Ablauf gebe ich diesen dann jeweils wieder frei.

Es funktioniert so wie es soll, und ich bedanke mich nochmals, bei allen, für die Hilfe.

Gruß

P.S. Es war eine gute Entscheidung, mir dieses Forum für meine Fragen auszusuchen - ich komme gerne wieder... :-)

P.P.S. Wo kann man euren Renommee-Modifikator erhöhen? :rolleyes:
 
Hi.
Es funktioniert so wie es soll, und ich bedanke mich nochmals, bei allen, für die Hilfe.
Bitte schön. :) Hab ich gern gemacht - vor allem da du dich auch selbst ernsthaft damit beschäftigt hast und nicht einfach nur fertigen Code haben wolltest...
P.P.S. Wo kann man euren Renommee-Modifikator erhöhen? :rolleyes:
Ich denke das passiert wenn du Beiträge positiv bewertest (das mittlere Icon unterhalb eines Beitrags auf der linken Seite). Siehe http://www.tutorials.de/forum/inter...-beitragsbewertung-und-benutzer-renommee.html

Gruß
 
Moin,
P.P.S. Wo kann man euren Renommee-Modifikator erhöhen?
Das kannst Du direkt gar nicht - der berechnet sich autromatisch!
Du kannst allenfalls einen Beitrag bewerten (links unter dem Beitrag der mittlere Button)! Neben Deiner - hoffentlich positiven :p - Bewertung, fließt dann Deiner eigener Renommee-Faktor in eine intern verwaltete Zahl ein, die den Faktor des Bewerteten ggf. erhöht! Da Du derzeit noch '0' hast also nicht wirklich!
Detaillierte Infos zu diesem Thema findest Du bspw. hier: http://www.tutorials.de/forum/feedback-forum/283221-renommee-meinungen-dazu.html und mit "Renommee" über die Suche!

Gruß
Klaus
 
Zurück