Moi...
Yritän täs ratkoa yhtä ohjelmoinnin lisätehtävää jossa käpistellään jonoa C kielellä. Koodi toimi niin pitkälle, kunnes mennään extract funktioon, jonka jälkeen alkaa tapahtua katastrofia. En vaan löydä syytä, miksi queue hajoaa..
Nähtävästi se koodarin ammatitauti eli koodisokeus iski.. :|
Yleensä koodi printtaa tämän:
extracting vikarivi head: vikarivi, tail: ekarivi extracting É7g head: É7g, tail: ekarivi extracting É7g head: É7g, tail: ekarivi extracting É7g head: É7g, tail: ekarivi
ja pitää pysäyttää jollain ctrl+C:llä. Taas +
ja tässä itse tuotos.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 20 typedef struct qelement *qpointer; typedef struct qelement { char name[ MAXLEN ]; qpointer next, previous; } qelement; qpointer insert(char *name, qpointer queue, qpointer *head, qpointer *tail) { qpointer new = (qpointer)malloc(sizeof(qelement)); strcpy(new->name, name); if(queue != (qpointer)NULL) { new->next = queue; queue->previous = new; (*head) = new; } else { new->next = new; (*head) = new; (*tail) = new; } new->previous = new; return new; } qpointer extract(qpointer queue, qpointer *head, qpointer *tail); qpointer extract(qpointer queue, qpointer *head, qpointer *tail) { qpointer qtail =(*head); if(queue == (qpointer)NULL) return (qpointer)NULL; else { if(queue->previous != queue) { free(queue); (*head)=NULL; (*tail)=NULL; return (qpointer)NULL; } else { queue->previous->next = queue->previous; if ( *head != (*head)->next ) *head = (*head)->next; free(queue); return qtail; } } } int main ( void ) { int i; qpointer qptr =NULL; qpointer head =NULL ; qpointer tail =NULL ; char teksti[MAX][MAXLEN] = { "ekarivi", "tokarivi", "kolmasrivi", "valirivi", "virherivi", "kommenttirivi", "vikarivi" }; /* insert into queue */ printf("\n queue tester \n"); for (i =0; i<= MAX-1 ; i++) { printf("\n insert %d: %s", i , teksti[i]); qptr= insert( teksti[i], qptr, &head, &tail); printf(" head: %s, ", head->name ? head->name : "no data"); printf(" tail: %s ", tail->name ? tail->name : "no data"); } /* code here */ /* remove from queue */ printf("\n ***\n"); while ( qptr != NULL ) { printf("\n extracting %s ",qptr->name); printf(" head: %s, ", head->name ? head->name : "no data"); printf(" tail: %s ", tail->name ? tail->name : "no data"); qptr = extract(qptr, &head, &tail); } return(0);
Kiitoksia vaivautuneille..
\\T.
Eipä ne ongelmat aina ratkea vain koodia tuijottamalla. Pitää debugata vaikeemmissa tilanteissa.
Äkkiseltään insert()-funktio näyttää erikoiselta. Mitä virkaa "qpointer queue"-parametrilla on jos se on aina NULL? Sama NULL pyörii sitäkautta pääohjelmassa.
muokkaus: Eipä tullu jostain syystä itellä mieleen että jotain muuta kuin NULL pyörähtää paluuarvon kautta -.- No joku jakso kattoa koko koodin tarkemmin.
Moi,
queue on NULL vain silloin, kun jono on tyhjä, jolloin sekä head & tail päivitetään. Seuraavilla kerroilla queue viittaa jonoon, joten viittaukset uuteen elementtiin asetetaan(->next, ->previous, head). Lisäksi insert() palauttaa aina uuden jonon elementin osoitteen (ok, on tuossa yksi virhe, malloc():n palautusarvoa ei testata koskaan, fixed), joten ei sitä NULL:ia juurikaan kierrätetä, jos nyt oikein ymmärsin argumenttisi.
Myönnän, että meni oma aikansa saada hahmotettua... Ja eclipse CDT /gdb debuggeria on käytetty, mut ei oikein sytytä, miksi juuri extract() toimii kuten toimii..
\\T.
Miksi jonon esittämiseen tarvitaan kolme muuttujaa, eikö pelkkä queue
riittäisi? Ilmeisesi head
osoittaa aina samaan jonon jäseneen kuin queue
tai qptr
, joten se on täysin turha. Myös tail
on aina tämän jäsenen previous
, joten sitäkään ei tarvita.
Muuttujien kryptisten nimien takia koodia on muutenkin turhan vaikea ymmärtää.
if(queue->previous != queue) { free(queue); (*head)=NULL; (*tail)=NULL; return (qpointer)NULL; }
Vertailun pitäisi olla ==.
queue->previous->next = queue->previous;
Tässä on logiikkavirhe ja myös queue->next->previous
pitäisi asettaa.
Lisäys:
Koodissa on niin paljon virheitä, etten jaksa listata niitä yksitellen. Tässä korjattu versio.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 7 #define MAXLEN 20 typedef struct qelement *qpointer; struct qelement { char name[ MAXLEN ]; qpointer next, previous; }; qpointer insert(qpointer queue, const char *name) { qpointer elem = malloc(sizeof(*elem)); strcpy(elem->name, name); if (queue != NULL) { elem->next = queue; elem->previous = queue->previous; queue->previous->next = elem; queue->previous = elem; } else { elem->next = elem; elem->previous = elem; } return elem; } qpointer extract(qpointer queue) { if (queue == NULL) return NULL; if (queue->previous == queue) { free(queue); return NULL; } queue->previous->next = queue->next; queue->next->previous = queue->previous; qpointer next = queue->next; free(queue); return next; } void print_queue(const qpointer queue) { if (queue == NULL) { printf("(empty)\n"); return; } printf("%s", queue->name); for (qpointer p = queue->next; p != queue; p = p->next) { printf(", %s", p->name); } printf("\n"); } int main(void) { int i; qpointer queue = NULL; char teksti[MAX][MAXLEN] = { "ekarivi", "tokarivi", "kolmasrivi", "valirivi", "virherivi", "kommenttirivi", "vikarivi" }; printf("queue tester\n"); for (i = 0; i < MAX; i++) { printf("insert %d: %s\n", i , teksti[i]); queue = insert(queue, teksti[i]); printf("queue = "); print_queue(queue); } printf("\n ***\n"); while (queue != NULL) { printf("extracting %s\n", queue->name); queue = extract(queue); printf("queue = "); print_queue(queue); } }
Kappas, poistanpa omani kun jlaire ahkeroi. Kaipa nyt tuli selväksi mikä on jonon ja pinon ero, koska se näkyi alkuperäisessä kysymyksessä olevan vähän epäselvä ohjelman tulostuksen kannalta.
Mielestäni koodia selkeyttää, jos tehdään ensin funktiot linkitetyn listan käsittelyyn ilman muistinhallintaa ja toteutetaan sitten tarvittaessa erikseen versiot, joissa on free ja malloc. Tällä tavalla funktiot ovat myös joustavammat: niillä voidaan esimerkiksi siirtää alkio listasta toiseen ilman muistin varaamista ja vapauttamista.
Hyvä pointti.
Aihe on jo aika vanha, joten et voi enää vastata siihen.