02. juni 2008 - 20:58Der er
32 kommentarer og 1 løsning
Linked list problem
Hej eksperten (/er).
Jeg sad og legede med linked lists i C, da jeg skal bruge det til et projekt, om et lille stykke tid. koden ser sådan ud. De meste ser ud til at virke som det skal men Next i mit struct bliver ikke opdateret rigtigt. Når jeg skal Koden ser sådan ud:
void addFirst(int i, struct node *insert, struct node *h){
insert->id = i;
if (head != NULL){ //hvis listen ikke er tom
insert->next = h; //den nye node skal pege på det som head pegede på før // !!insert->next = *h giver bus-error; FEJLEN LIGGER // FORMENTLIG HER!(?) } else { insert->next = NULL; }
Struct info: -------- head->id (global): 5 node->id: 5 node->next.id: NULL! ----------------------- Struct info: -------- head->id (global): 6 node->id: 6 node->next.id: 6 *** ----------------------- ***som det ses peger id 6 som nu er den forreste node på sig selv i stedet for på id 5
linkedListBasic.c: In function ‘addFirst’: linkedListBasic.c:33: error: request for member ‘next’ in something not a structure or union linkedListBasic.c:40: error: incompatible types in assignment
erhm...det er jo et helt andet eksempel. Hvis jeg skal forstå hvordan det virker så nytter det jo ikke så meget (har set flere kode eksempler på nettet, men jeg kan ikke finde ud af hvad der er galt med min kode.)
Jeps der har jeg været før, det andet var en forsøgt lappeløsning da jeg ikke kunne få det til at fungere.. hvorfor bruger du malloc? kan det ikke lade sig gøre uden?
Har omstruktureret efter dine (arne v's) anvisninger (venter lige med malloc dog, med mindre det er den som er problemet). Men som sagt har været her før, det giver også præcis samme output som jeg pastede ind i toppen..
void addFirst(int i, struct node **h){
struct node nyNode; nyNode.id = i;
if (*h != NULL){ //hvis listen ikke er tom
nyNode.next = *h; //hvis jeg udkommenterer denne bliver next = NULL, på den sidste node, og nyNode.next = **h //vil compileren ikke være med til såå nogen gode idéer? } else { nyNode.next = NULL; }
*h = &nyNode; structInfo(nyNode, *h); }
alt andet end: nyNode.next = *h; ser ud til at opføre sig som det skal..
Nå har fundet fejlen, det var selvfølgelig en mindre tanketorsk. Problemet var at jeg (som arne v, i virkeligheden også var inde på), at jeg opretter Noderne lokalt når addFirst køres. Dvs. de bliver lagt i addFirst's stack (som jo er lokal) og når vi kommer tilbage til mainmetoden igen, peger head på noget som måske allerede er blevet ændret eller i hvertfald med stor sandsynlighed bliver det næste gang addFirst bliver kørt. Den simpleste løsning er, at oprette noden i main, og derefter sende referencen til den node som skal oprettes i listen + ref. til head til addFirst. Så længe mainmetoden kører (og det gør den så længe programmet kører, ligger alle noderne (dvs. hele den linkede liste) i main metoden stack og det vil derfor virke. Den lidt smukkere metode er måske (som arne v også var inde på) at bruge malloc til at at allokere plads til noderne i heap'en. Anyway, arne v da du har ledt mig på rette spor synes jeg du skal have points'ne, så smid et svar, hvis du vil have points:)..
Hmm...ser dog lige med friske øjne at nok har været en anden..
Hvis en kan give den fede og pædagogiske forklaring, smider jeg gerne points'ne der (eftersom det ikke ser ud til at arne v, dukker op, og jeg desuden egentlig løste det ved at gå et stykke tilbage og bygge det op endnu engang, og ikke rigtigt forstod hans forklaring)..
well kom frisk! den gode og pædagogiske pointer udredning, er der helt sikkert mange som vil værtsætte så det er helt klart 200 point værd fra mig.
Det kan godt være at struct node *head; peger et tilfældigt sted i memory, men den bliver tilgengæld ved med at pege det samme tilfældige sted, da den ligger i main metoden. head->next //nope der ligger head. prøv at kør denne (indsætter lidt flere noder og kører printLint, ellers er koden den samme).
void addFirst(struct node *add, struct node *head){ printf("addfirst: pointeren head ligger på addresse %p\n", &head); printf("addfirst: pointeren head peger på addresse %p\n", head);
if (head->next != NULL){ add->next = head->next; }
Det virker dog perfekt i gcc 4.01 på Mac output: main: pointeren head ligger på addresse 0xbffffa00 main: pointeren head peger på addresse 0x0 addfirst: pointeren head ligger på addresse 0xbffff9bc addfirst: pointeren head peger på addresse 0xbffffa00 addfirst: pointeren head ligger på addresse 0xbffff9bc addfirst: pointeren head peger på addresse 0xbffffa00 addfirst: pointeren head ligger på addresse 0xbffff9bc addfirst: pointeren head peger på addresse 0xbffffa00 addfirst: pointeren head ligger på addresse 0xbffff9bc addfirst: pointeren head peger på addresse 0xbffffa00 Hele den linkede liste (id'er): --- 4 3 2 1 --------------- debug: main: pointeren head ligger på addresse 0xbffffa00 //her ligger head main: pointeren head peger på addresse 0x0 //peger ikke på noget endnu
addfirst: pointeren head peger på addresse 0xbffffa00 //(peger på den adresse i main hvor head ligger (som stadig er // den samme)) addfirst: pointeren head ligger på addresse 0xbffff9bc //dette er jo addFirst's lokale pointer til main's head, derfor har den //en anden adresse
Hvad mener du med at din gcc crasher? kommer den op med nogen fejl?
Anyway, hvis det du ville var at se hvad den virkelige 'head' (fra mainmetoden) peger på skal det jo være sådan:
void addFirst(struct node *add, struct node *head){ printf("addfirst: pointeren head ligger på addresse %p\n", &head); printf("addfirst: pointeren (lokal) head peger på addresse %p\n", head); printf("addfirst: pointeren head (main) peger på addresse %p\n", head->next);
if (head->next != NULL){ add->next = head->next; }
main: pointeren head ligger på addresse 0xbffffa00 main: pointeren head peger på addresse 0x0 addfirst: pointeren head ligger på addresse 0xbffff9bc addfirst: pointeren head peger på addresse 0xbffffa00
saa ser du at nede i addfirst peger dens head paa det sted i memory hvor der kun ligger en pointer ikke en struct.
Og det betyder at naar addfirst opdaterer i den struct saa overskriver den det memory som tilfaeldigvis ligger efter head i main.
----
Hvis du lod prototypen for addFirst angive argumenter, saa ville compileren ogsaa brokke sig.
----
struct node *head = &h;
faar head til at pege paa noget validt. Men det loeser ikke problemet, da det ikke er det som head peger paa, men derimod det lige efter head som bliver overskrevet.
>saa ser du at nede i addfirst peger dens head paa det sted i memory hvor der kun ligger en pointer ikke en struct.<
Præcis, den peger på main's head som er en pointer.
>Hvis du lod prototypen for addFirst angive argumenter, saa ville compileren ogsaa brokke sig.<
Det må du nok udspecificere. Prototypen, lyder lidt som java-tankegang, jeg instantierer den jo ikke ligefrem (måske mener du noget helt andet(?)).
>faar head til at pege paa noget validt. Men det loeser ikke problemet, da det ikke er det som head peger paa, men derimod det lige efter head som bliver overskrevet.<
'head' peger lige nu på en 'dummy struct'. Som sagt min gcc har ingen problemer her, men jeg lavede det i tilfælde af, at ældre compilere ikke kan lide at det det er uspecificeret hvor en pointer peger hen..
Jeg har desuden svært ved at forestille mig hvordan en linked liste kan blive til hvis headpointeren ikke virker efter hensigten, og hvorfor det virker giver også fint mening for mig:
output:
main: pointeren head ligger på addresse 0xbffffa00 //her ligger den officielle 'head' i main's stack, denne bliver liggende her main: pointeren head peger på addresse 0xbffff9f8 //den peger nu på dummystruct'et 'head' (da jeg har updateret koden med //indlæg fra 18:50:15)
addfirst: pointeren (lokal) head ligger på addresse 0xbffff9bc /*Denne pointer bliver deklareret som argument til addFirst. Hvis f.eks. vi har en metode: minMetode(int x, int *yPointer){} bliver 'x' og 'yPointer' lagt i 'minMetode's stack. int'en indeholder (formentlig) en int værdi, mens pointeren indeholder en adresse. Altså er 'yPointer' lokal lige så vel som 'x'. I mit linked list tilfælde hedder de bare begge head (for at forvirre mest muligt....(joke:)). */
addfirst: pointeren (lokal) head peger på addresse 0xbffffa00 //dette er addFirst's adresse til head'pointeren i main
addfirst: pointeren head (main) peger på addresse 0x0 //dette er den officielle 'head' som ikke endnu peger på noget endnu addfirst: pointeren (lokal) head ligger på addresse 0xbffff9bc //placeringen af addFirst's lokale pointer er naturligvis //uændret addfirst: pointeren (lokal) head peger på addresse 0xbffffa00 //peger stadig på main's head (som forventet) addfirst: pointeren head (main) peger på addresse 0xbffff9d8 //dette er adressen til den nye node som skal indsættes addfirst: pointeren (lokal) head ligger på addresse 0xbffff9bc //same same (se sidste gang adressen var repræsenteret) addfirst: pointeren (lokal) head peger på addresse 0xbffffa00 //peger stadig på main's head (som forventet) addfirst: pointeren head (main) peger på addresse 0xbffff9e0 //ny node... addfirst: pointeren (lokal) head ligger på addresse 0xbffff9bc //same same (se sidste gang adressen var repræsenteret) addfirst: pointeren (lokal) head peger på addresse 0xbffffa00 //peger stadig på main's head (som forventet) addfirst: pointeren head (main) peger på addresse 0xbffff9e8 //ny node.. Hele den linkede liste (id'er): --- 4 3 2 1 --------------- Voila! ikke (for mig) overraskende en linked liste..
Jeps du har ret i 04:06:43, den havde jeg overset tak for det! med hensyn til 04:07:17, er det jo ikke forkert, der bare flere måder at implementere en linked liste på, og head bliver desuden opdateret som den skal.
Men tak for diskussionerne, det har da trukket mig godt og grundigt rundt i stoffet må man sige! Jeg synes du fortjener nogle points så smid et svar, hvis du vil have dem, (og så kan vi få lukket debatten:)..
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.