Pointers über Pointers ;-)

  • Hallo!

    Ich muss gestehen, ich bin kein C Profi. Daher quält mich folgendes Problem:

    ich habe zwei Pointer Listen, welche mir "quasi" auf die selben Objekte x zeigen. eine "Mutterliste", sie zeigt direkt auf alle Objekte x. Und eine "Kindliste", sie zeigt nur auf einige Objekte meiner Mutterliste, doch sie zeigt nicht auf diese Objekte im eigentlichen sinne (direkt), sondern nur indirekt auf ein struct (und dieses struct zeigt direkt auf ein Objekt x).

    was passiert nun, wenn ich ein objekt von meiner Mutterliste gelöscht habe - wohin zeigt der Pointer meiner Kindliste, welche ursprünglich auf dieses Objekt gezeigt hat? Frage1. Frage2: muss ich diesen Pointer meiner Kindliste nicht auch über "free" loslösen? und wenn, versucht es dann auch, dass objekt x zu "löschen" (aus dem heap)

    hm.. vielleicht ist es auch nur spät..

    danke, alex

  • ich habs so verstanden, bsp:
    speicher: 0123456789
    element der "mutterliste" zeigt auf 0
    element der "kindliste" auf 3

    afair:
    wenn du jetzt free(element "mutterliste") aufrufst, dann ist 0-9 weg.

    wenn du dann auf den bereich, auf den das element der "kindliste" zeigt, zugreifst, erhältst du eine speicherverletzung.

    mfg, west.

  • struct x{

    }

    x *pointer_auf_x;

    struct y{

    x * pointer_auf_x;

    }

    y *pointer_auf_y;

    jetzt hab ich zwei listen, meine mutterliste aus einer einfach verketteten liste auf x. und eine kindliste, eine liste auf y.

    die frage ist, wenn ich jetzt ein element aus der mutterliste lösche, was passiert mit meiner liste aus y? oder umgekehrt: was passiert, wenn ich bsp. free(pointer_auf_y) mache? -> wird dann auch das objekt meiner mutterliste gelöscht?

  • x *ptrX = new x();

    y *ptrY = new y();
    ptrY->ptrX = ptrX;

    delete ptrX;

    ab jetzt ist ptrY->ptrX undefiniert, d.h. bei Verwendung dessen kann es zu einer Speicherverletzung kommen, wie schon west erläutert hat. Der prtY->ptrX zeigt quasi irgendwohin. Wenn du ptrY->ptrX freigibst wird auch der Speicher von ptrX freigeben. Eine Freigabe könnte so aussehen:

    ptrY->ptrX = NULL;
    delete ptrX;
    ptrX = NULL;
    delete ptrY;
    ptrY = NULL;

    mfG Fup

  • von c weiss ichs, von c++ nicht (wird aber vermutlich genauso sein):

    free() auf einen pointer gibt den dahinterliegenden speicher frei. free() lässt sich nur auf einen pointer anwenden, der von malloc(), calloc() oder realloc() zurückgegeben wurde. soweit so gut.
    der pointer selbst wird bei free() NICHT auf null gesetzt. (das geht bei c überhaupt nicht. -> Stichwort "call by value").
    free() hat auch keinen return value. afair: bei free() kann man von erfolgreicher durchführung ausgehen.

    (die "nice code"-konvention sagt, dass man nach einem free() den pointer auf null setzen soll. vorteil: wenn nochmal free() aufgerufen wird, passiert nichts.)

    > man 3 free

    Zitat

    DESCRIPTION
    free() frees the memory space pointed to by ptr, which must have been returned by a previous call to
    malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, unde-
    fined behaviour occurs. If ptr is NULL, no operation is performed.

    Zitat

    RETURN VALUE
    free() returns no value.

    mfg, west.

  • Weil head_alarm nicht NULL ist. Wie schon erwähnt zeigt er irgendwo hin.

    mfG Fup

  • Zitat von Fup

    Weil head_alarm nicht NULL ist. Wie schon erwähnt zeigt er irgendwo hin.



    vielen dank einmal für die antworten. es wundert mich nur, dass ich obwohl ich free(head_alarm) schreibe, "danach" immer noch auf head_alarm zugreifen kann!

  • der pointer selber gehoert noch dir. der referenzierte bereich aber nicht mehr und kann dir vom OS jederzeit weggenommen werden, d.h. man produziert nicht in allen faellen eine speicherverletzung. (manche OS räumen erst auf, wenn der platz benötigt wird. manche sofort. voodoo.)

    mfg, west.

  • Zitat von sommeralex

    vielen dank einmal für die antworten. es wundert mich nur, dass ich obwohl ich free(head_alarm) schreibe, "danach" immer noch auf head_alarm zugreifen kann!

    Bei kleineren Allozierungen reserviert malloc meistens gleich einen größeren Block, und returnt aus diesem Block heraus Speicherplätze wenn noch mehr Platz ist drinnen. Dadurch wird der overhead kleiner gehalten.
    Dieses Verhalten ist allerdings nicht genauer spezifiziert, und man kann sich daher nicht drauf verlassen (weder zwischen OS, noch zwischen Computern, nichtmal zwischen Mondphasen am gleichen Computer).

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • Zitat von west

    der pointer selber gehoert noch dir. der referenzierte bereich aber nicht mehr und kann dir vom OS jederzeit weggenommen werden, d.h. man produziert nicht in allen faellen eine speicherverletzung. (manche OS räumen erst auf, wenn der platz benötigt wird. manche sofort. voodoo.)



    danke - jetzt ist es klar! es wird qasi als "gelöscht markiert" ok. jetzt ist aber immer noch meine frage offen:

    wenn ein struct X auf andere structs Y zeigt, und ich dieses struct X mit free(struct X) anschreibe, werden dann auch meine structs Y "gelöscht"/free - obwohl noch andere zeiger auf diese zeigen?

    aber wie lösche ich nun "nur" die zeiger? (ohne die objekte zu löschen, auf die sie zeigen)

  • Zitat von sommeralex

    wenn ein struct X auf andere structs Y zeigt, und ich dieses struct X mit free(struct X) anschreibe, werden dann auch meine structs Y "gelöscht"/free - obwohl noch andere zeiger auf diese zeigen?

    Generell wird nichts gelöscht, was du ihm nicht sagst. Dir kanns auch passieren, dass du Speicher reserviert hast, auf den du keinen Pointer mehr hast, das ist dann ein memory leak.
    C und C++ haben per default keine garbage collection wie Java, Haskell und andere Sprachen!

    Am besten ist es, wenn du Pointer als normale Variablen ansiehst, die eine Speicheradresse als Inhalt haben (was ja auch wirklich der Fall ist). malloc() reserviert einen Block im Speicher und gibt die Anfangsadresse zurück. Irgendwann musst du genau diese Anfangsadresse wieder free() übergeben, dann wird der komplette Block wieder freigegeben. Mehr Magie passiert nicht (aus der Sicht des Programmierers).

    Zitat

    aber wie lösche ich nun "nur" die zeiger? (ohne die objekte zu löschen, auf die sie zeigen)

    meinzeiger = NULL;

    was äquivalent ist zu meinevariable = 0; bei Integer-Typen.

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • also:

    ich habe eine liste, bestehend aus struct x, einfach verkettet. ich initialisiere diese zur laufzeit mit malloc - bis dahin ist mir alles klar.

    ich möchte nun zusätzlich noch eine liste, aus struct y (und struct y enthält struct x zeiger, diese zeigen alle auf die vorher schon erstellte liste bzw. objekte meiner liste)

    muss ich diese 2.liste über ein malloc initiieren? oder nicht? die zeiger, auf die dieses struct y liste zeigen, sind alle schon über ein malloc meiner 1.liste erzeugt worden, und daher persistent.

    wenn ich nun struct y "free" befehle, wirkt sich dass auch auf meine liste x aus? wenn ich die struct y liste über malloc initiiert habe, muss ich sie ja mit free loswerden. vielleicht muss ich aber gar nicht diese liste über ein malloc deklarieren, oder?

    ist ungefähr klar, worauf ich hinaus will?

  • Zitat von sommeralex

    ich möchte nun zusätzlich noch eine liste, aus struct y (und struct y enthält struct x zeiger, diese zeigen alle auf die vorher schon erstelle liste bzw. objekte meiner liste)

    muss ich diese liste über ein malloc initiieren? oder nicht? die zeiger, auf die dieses struct y zeigen, sind alle schon über ein malloc erzeugt worden.

    Generell ist der Inhalt des Speicherbereichs völlig egal. free schaut sich nicht an, was da drinnen liegt (und für free selber ist es ja nur ein Haufen von Bytes ohne Bedeutung).

    Zitat

    wenn ich nun struct y "free" befehle, wirkt sich dass auch auf meine liste x aus?

    Gar nicht.

    Zitat

    wenn ich die struct y liste über malloc initiiert habe, muss ich sie ja mit free loswerden.

    Richtig.

    Zitat

    vielleicht muss ich aber gar nicht diese liste über ein malloc deklarieren, oder?

    Naja, irgendwoher muss der Speicher kommen, wo du das hinspeicherst. Speziell in C++ gibts da viele andere Methoden, aber in C greift man bei sowas eigentlich immer auf malloc zurück.

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • Zitat von sommeralex

    kann es vielleicht sein, dass ich nur den "speicher meines pointers" über free loswerden muss? also free(&pointer) ???

    nur wenn du den Speicher deines Pointers vorher alloziert hast mit malloc, also sowas in der Art wie &pointer = malloc(sizeof(&pointer));. Das geht aber nur in C++ mit seinen Referenzen.

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • danke mal für die antwort.

    struct x{

    struct y *pointer;
    char[] reason;

    struct x *next;
    }

    struct y{

    int blabla;
    struct y *next;

    }

    ich erzeuge eine liste Y über malloc. dann iteriere ich über diese liste in gewissen abständen. falls manche objekte diese liste in meine auswahl kommen, möchte ich eine neue liste erstellen, mit einer struct X liste, in welcher zusätzlich der "grund"/reason gespeichert wird, warum dieses objekt aufgenommen wurde.

    also erstelle ich auch über malloc meine liste struct X. wenn ich nun ein "objekt" über free loswerden will, frage ich mich aber immer noch, was da WIRKLICH passiert? wenn sich das NICHT auf meine Y Liste auswirkt, was passiert dann überhaupt?

    Außerdem: wenn ich malloc X mache, bedeutet es doch, dass Speicherplatz sowohl für mein char[] als auch für meinen pointer next und pointer "pointer" RESERVIERT WIRD. da das objekt "pointer" aber sowieso schon besteht, ist es doch, als würde der platz "doppelt" bzw unnötig reserviert werden???

  • Du verwechselst den Speicherplatz, den der pointer selber beansprucht mit dem, auf den er zeigt. Ein Pointer ist eine Datenstruktur, die üblicherweise 4 Byte groß ist (auf 16bit-Systemen 2 Byte, auf 64bit-Systemen 8 Byte, etc). Auch dafür muss man Speicher reservieren.

    Nochmal: Stell dir vor da würde kein Pointer stehen, sondern ein int. Dann verwirrt es dich vielleicht weniger :)

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • Vielleicht hilft es dir, wenn du einen passenden Debugger hernimmst und dir die Werte und Speicherbereiche anzeigen lässt. Ein selbstgetesteter Code sagt mehr als tausend Worte.

    mfG Fup

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!