C: return pointer naar struct, struct heeft pointer naar locale struct T_T

Status
Niet open voor verdere reacties.

That Guy

Meubilair
Lid geworden
28 nov 2006
Berichten
5.010
Goedenavond allemaal,


Sinds kort bezig met C. Nu ben ik druk bezig met programmeren en tot nu toe gaat het, met vallen en opstaan, best goed. Nu zit ik met de volgende vraag;
Ik heb een functie die een pointer naar een struct retourneerd. Nu had ik deze struct aangemaakt in de functie, zoiets:
[CPP]somestruct * bbq(...)
{
somestruct foo;

// hier allemaal magie

return &foo; // oid; het returnde iig een pointer naar foo.
}[/CPP]
nu kreeg ik steeds de fout: warning: function returns address of local variable [enabled by default]
Nu snap ik dat foo lokaal wordt gemaakt, en deze dus weg is op het moment dat de functie klaar is. (overigens 'werkte' dit wel en kon ik 't later gewoon gebruiken... ?! dit snap ik dus ook niet...)

Nu heb ik dit opgelost door dit te doen:
[CPP]somestruct * bbq(...)
{
somestruct * foo = malloc( sizeof(somestruct) );

// weer allemaal magie...

return foo;
}[/CPP]
En dit werkt verder prima.

Ohja, daarnaast: ik kan nu toch gewoon later free() aanroepen buiten de functie?


Nu, de grote vraag is dit: waarom kan ik (zonder errors) wel dit doen? Overigens: somestruct ziet er ongeveer zo uit:
[CPP]typedef struct .....
{
another_struct * asp; // wijs naar een another_struct
....
} somestruct;[/CPP]en another_struct:[CPP]typedef struct .....
{
int iets;
char * ietsanders;
....
} another_struct;[/CPP]
[CPP]somestruct * bbq(...)
{
somestruct * foo = malloc( sizeof(somestruct) );

// bar is een another_struct
another_struct bar; // let op: bar is lokaal! in deze functie!

// geef spul een waarde
bar.iets = 3;
bar.ietsanders = "een string";

// okay, foo.asp wijst nu naar bar...
foo->asp = &bar;


return foo;
}[/CPP]
MAAR! als bar ook in de functie gemaakt wordt, waarom geeft GCC dan geen error? Of eigenlijk: waarom werkt dit wel?


Alvast bedankt!
 
Laatst bewerkt:
Als je geheugen binnen de functie declareert met malloc of met new (C++) dan komt dat op de heap.
Een locale variabele die je in een functie declareert komt op de stack en verdwijnt weer als de functie returnt.
Als je dan een pointer (of een adres) naar deze variabele teruggeeft, ontstaat er een zeer gevaarlijke situatie omdat het er, zoals je al zegt, op lijkt of alles goed gaat.
De fout is dan ook niet altijd snel te vinden.
Maar dat het fout zal gaan is wel zeker: het geheugen op de stack zal eerder of later overschreven worden.
Dit wordt dangling genoemd en neem mij niet kwalijk, wordt gezien als een blunder.

Ook het declareren op de heap met malloc of new is geen goede oplossing omdat je dan jezelf, of een gebruiker van jouw functie verplicht om de ruimte buiten de functie vrij te geven.
Als jouw functie een memberfunctie is, zal je in de declaratie van de klasse of struct moeten vermelden dat die variabele vrij gegeven moet worden,
iets wat niet erg professioneel staat en niet gewaardeerd wordt.
 
Laatst bewerkt:
Hey PlusPlus,


bedankt voor je input.
Maar dat het fout zal gaan is wel zeker: het geheugen op de stack zal eerder of later overschreven worden.
Ah, vandaar. Dat snap ik nu.
Ook het declareren op de heap met malloc of new is geen goede oplossing omdat je dan jezelf, of een gebruiker van jouw functie verplicht om de ruimte buiten de functie vrij te geven.
Ik had ergens (op de internets) gelezen dat je dan een pointer naar een struct (of iets anders for that matter), zoiets:
[CPP]void bbq(...., somestruct *iets)[/CPP]of
[CPP]void bbq(...., somestruct &iets)[/CPP]
Nu snap ik dat dit werkt, en dat je dan in je main (of iig buiten bbq) dus de struct maakt en deze meegeeft, a la
[CPP]somestruct sauce, *sp;
sp = &sauce;
bbq(..., sp); // oid?[/CPP]
Maar hoe is dit dan te doen met de another_struct? Deze wordt namelijk in bbq(), dynamisch, gemaakt.



Iets meer info:

somestruct is een node in een linked list. Deze heeft een waarde (een another_struct) en een pointer naar het volgende item. Nu moet de bbq() functie dus een linked list opbouwen, en het 1e item in deze linked list returnen (zodat main() er doorheen kan lopen oid).
Hoe kan bbq() nou dus meerdere another_structs maken en deze in meerdere somestructs gooien (en de 1e returnen)? Zonder het bovengenoemde danglen?



Alvast bedankt.



edit: het enige wat ik zelf kan bedenken is aan het einde van m'n prog, door de linked list lopen en elke keer de another_struc free()'en, dan 't linked list item free()'en, en naar de volgende stappen in de list. Is dit een goede oplossing? Als in, is er een... makkelijkere... manier?
 
Laatst bewerkt:
Ja, ik moet wel toegeven dat je er met zo'n enkelgelinkte lijst er in C niet aan ontkomt om in een functie geheugen op de heap te declaren en in een andere functie vrij te geven.

Hier volgt een door mij zo juist gescheven (getest) programma dat demonstreert hoe je een lijst zou kunnen opbouwen, raadplegen en afbreken.

#include <stdio.h>
#include <stdlib.h>

struct node{
int iets;
struct node* volgende;
};

struct node* voegtoe(int getal, struct node* ingang){
struct node* ptr = (struct node*) malloc(sizeof(struct node));
ptr -> iets = getal;
ptr -> volgende = ingang;
ingang = ptr;
return ingang;
}

void loopLijst(struct node* ingang){
struct node* hulp;
hulp = ingang;

while(hulp)
{ printf("\n%d", ingang -> iets);
ingang = ingang -> volgende;
free(hulp);
hulp = ingang;
}
}

int main(){
struct node* entry;
entry = NULL;
int i = 10;

printf("De lijst wordt nu opgebouwd en gelijk gevuld met getallen 1o t/m 1.");

while(i > 0)
{ entry = voegtoe(i, entry);
i--;
}

printf("\nDe lijst wordt nu omgekeerd afgedrukt en afgebroken.\n\n");

loopLijst(entry);

printf("\n\nOm dit goed te snappen, raad ik je aan om met pen\n");
printf("en papier de vakjes met pointers te tekenen.\n");
printf("\nGroetjes, PlusPlus\n\n");

system("PAUSE");

return 0;
}
 
Laatst bewerkt:
Hi PlusPlus,


Super! Heel erg bedankt.
Ik had al op een kladje een mooie tekening gemaakt van alle items in de linked list, inclusief pointers naar 't datastructuur waar elk item naar linkt :). Heb nu een losse functie gemaakt die de 1e node inneemt en de gelinkte structs een voor een leegmaakt en dan zelfzelf ook wist.
 
Laatst bewerkt:
Als je deze lijst die ik geschreven heb, stap voor stap gaat tekenen aan de hand van het programma, zal je er achter komen dat de vakjes of nodes steeds voor de vorige worden gezet bij het opbouwen van de lijst.
Dus op papier links ervan.

Succes,

PlusPlus
 
Status
Niet open voor verdere reacties.

Nieuwste berichten

Terug
Bovenaan Onderaan