Avatar billede tchami Nybegynder
23. oktober 2003 - 18:24 Der er 43 kommentarer og
1 løsning

C: Splittelse af linked list i to

Hej,

Jeg er stødt ind i (endnu) et problem ved brugen af linked list.

Jeg skal have sorteret min liste, og det har jeg fundet ud af at gøre (håber og tror jeg), men før jeg kan gøre det er jeg nødt til at dele min linkede liste op i to. En liste der indeholder det første element i den originale liste og en anden liste der indeholder de resterende elementer fra den originale liste.

Jeg har forsøgt mig frem og tilbage med i funktionen orderlist, men lige langt kommer jeg. Det ender hele tiden med at programmet crasher så snart jeg prøver at udskrive listen med de resterende elementer. Listen med det første element i den nye liste ser ud til at virke, men som sagt ikke den anden.

I stedet for en løsning af fejlen ville jeg blive glad hvis nogle kunne guide mig på rette vej, men hvis jeg er helt ude i hampen med mit forslag er en løsning selvfølgelig også helt i orden :)

Jeg er godt klar over at jeg slet ikke behøver en linked liste, men det er nu engang den måde jeg vil gøre det på :)

Herunder er koden:


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

struct node{
    char* name;
    int grade;
    struct node* next;
};

typedef struct node Node;

Node *makestartlist();
void gradelist(Node* node);
void orderlist(Node* node);

main(){

    int choice, count;
    char quit;
    Node* nodelist;

    //Make default linked list
    nodelist = makestartlist();

    do{

        // User-interface
        printf("3. Order list in increasing order of the grades\n");
        printf("7. Stop\n");

        scanf("%d", &choice);

        switch (choice) {
        case 3 :
                orderlist(nodelist);
                break;
        case 7 :
                break;
        default :


                break;
        }


    } while(choice != 7);

}

Node *makestartlist(){

    int i;
    Node *first=NULL, *parent=NULL, *node;

    // Declare array of structs
    Node students[10] = {
        {"Lars",0},
        {"Bent",3},
        {"Hans",5},
        {"Lise",6},
        {"Lone",7},
        {"Inger",8},
        {"Bo",9},
        {"Else",10},
        {"Atli",11},
        {"Jens",13}
    };

    for (i=0; i<10 ;i++){
        node = (Node*)malloc(sizeof(Node)); //Allocate memory
        if (i == 0) first = node;
        node -> name = students[i].name; //Add name
        node -> grade = students[i].grade; //Add grade
        node -> next = NULL;
        if (i>0) parent -> next = node;
        parent = node;
    }

    return first;
}

void gradelist(Node* node){

    printf("\n**********Show grade list*************\n");

    //Print linked list
    if (node != NULL){
        while(node != NULL){
            printf("Student: %s\tGrade: %d\n", node->name, node->grade);
          node = node->next;
        }
    }
    else {
        printf("No students!");
    }

    printf("****************************************\n\n");

}

void orderlist(Node* node){

    /*
    head contains the first element from the original linked list
    remaining contains the rest of the list
    */
    Node *head=NULL, *remaining, *first=NULL;
    int i = 0, headlistlength;

    printf("Order list in increasing order\n");

    // Split list in two
    while (node != NULL){
        if (i == 0){
            head = (Node*)malloc(sizeof(Node));
            head->name = node->name;
            head->grade = node->grade;
            head->next = NULL;
        }
        else {
            remaining = (Node*)malloc(sizeof(node));
            if (i == 1) first = remaining;
            remaining->name = node->name;
            remaining->grade = node->grade;
        }
        node = node->next;
        i++;
    }

    gradelist(first);
}
Avatar billede arne_v Ekspert
23. oktober 2003 - 18:35 #1
Så vidt jeg kan se får du ikke sat remaining->next ...
Avatar billede arne_v Ekspert
23. oktober 2003 - 18:36 #2
Node *parent = NULL;

...

            remaining = (Node*)malloc(sizeof(node));
            if (i == 1) first = remaining;
            remaining->name = node->name;
            remaining->grade = node->grade;
            remaining->next = NULL;
            if(parent != NULL) parent->next = remaining;
            parent = remaining;
Avatar billede tchami Nybegynder
23. oktober 2003 - 18:40 #3
Det har jeg også prøvet, men får stadig fejl.

Det er iøvrigt gradelist(first) jeg skal kalde og ikke gradelist(remaining) efter løkken ikke?
Avatar billede arne_v Ekspert
23. oktober 2003 - 18:52 #4
Samme fejl ?

Jo.
Avatar billede arne_v Ekspert
23. oktober 2003 - 18:54 #5
Det virker altså hos mig !
Avatar billede arne_v Ekspert
23. oktober 2003 - 18:54 #6
#include<stdio.h>
#include<stdlib.h>

struct node{
    char* name;
    int grade;
    struct node* next;
};

typedef struct node Node;

Node *makestartlist();
void gradelist(Node* node);
void orderlist(Node* node);

main(){

    int choice, count;
    char quit;
    Node* nodelist;

    //Make default linked list
    nodelist = makestartlist();

    do{

        // User-interface
        printf("3. Order list in increasing order of the grades\n");
        printf("7. Stop\n");

        scanf("%d", &choice);

        switch (choice) {
        case 3 :
                orderlist(nodelist);
                break;
        case 7 :
                break;
        default :


                break;
        }


    } while(choice != 7);

}

Node *makestartlist(){

    int i;
    Node *first=NULL, *parent=NULL, *node;

    // Declare array of structs
    Node students[10] = {
        {"Lars",0},
        {"Bent",3},
        {"Hans",5},
        {"Lise",6},
        {"Lone",7},
        {"Inger",8},
        {"Bo",9},
        {"Else",10},
        {"Atli",11},
        {"Jens",13}
    };

    for (i=0; i<10 ;i++){
        node = (Node*)malloc(sizeof(Node)); //Allocate memory
        if (i == 0) first = node;
        node -> name = students[i].name; //Add name
        node -> grade = students[i].grade; //Add grade
        node -> next = NULL;
        if (i>0) parent -> next = node;
        parent = node;
    }

    return first;
}

void gradelist(Node* node){

    printf("\n**********Show grade list*************\n");

    //Print linked list
    if (node != NULL){
        while(node != NULL){
            printf("Student: %s\tGrade: %d\n", node->name, node->grade);
          node = node->next;
        }
    }
    else {
        printf("No students!");
    }

    printf("****************************************\n\n");

}

void orderlist(Node* node){

    /*
    head contains the first element from the original linked list
    remaining contains the rest of the list
    */
    Node *head=NULL, *remaining, *first=NULL, *parent=NULL;
    int i = 0, headlistlength;

    printf("Order list in increasing order\n");

    // Split list in two
    while (node != NULL){
        if (i == 0){
            head = (Node*)malloc(sizeof(Node));
            head->name = node->name;
            head->grade = node->grade;
            head->next = NULL;
        }
        else {
            remaining = (Node*)malloc(sizeof(node));
            if (i == 1) first = remaining;
            remaining->name = node->name;
            remaining->grade = node->grade;
            remaining->next = NULL;
            if(parent != NULL) parent->next = remaining;
            parent = remaining;
        }
        node = node->next;
        i++;
    }

    gradelist(first);
}
Avatar billede tchami Nybegynder
23. oktober 2003 - 18:56 #7
Jeps, programmet crasher og windows spørger om det skal sende en fejlmelding.
Avatar billede tchami Nybegynder
23. oktober 2003 - 19:01 #8
Hmm, mystisk. Jeg får denne fejl nu:

Application Error
The instruction at "0x77f5847c" referenced memory at "0xffffffff". The memory could not be "read".

Kunne det eventuelt ha' noget at gøre med compileren? Jeg bruger Dev-C++'s GNU compiler..
Avatar billede arne_v Ekspert
23. oktober 2003 - 19:03 #9
Næppe.

Jeg bruger også GCC.

Har du prøvet med den version jeg postede ?
Avatar billede tchami Nybegynder
23. oktober 2003 - 19:07 #10
Jeps, samme resultat.
Avatar billede arne_v Ekspert
23. oktober 2003 - 19:16 #11
Når jeg kører det jeg postede i dev-cpp får jeg:

3. Order list in increasing order of the grades
7. Stop
3
Order list in increasing order

**********Show grade list*************
Student: Bent  Grade: 3
Student: Hans  Grade: 5
Student: Lise  Grade: 6
Student: Lone  Grade: 7
Student: Inger  Grade: 8
Student: Bo    Grade: 9
Student: Else  Grade: 10
Student: Atli  Grade: 11
Student: Jens  Grade: 13
****************************************

3. Order list in increasing order of the grades
7. Stop
Avatar billede tchami Nybegynder
23. oktober 2003 - 19:42 #12
Jeg har pastet det ind du postede og får føromtalte fejl.

Den når lige at skrive linien printf("Order list in increasing order\n"); ud og så er der dømt Application Error.

Hvis jeg derimod fjerner remaining->next = NULL; kan den udskrive listen, men kun én gang. Hvis jeg vælger at sortere listen igen, udskriver den også listen, men jeg får denne fejl før den springer ud af orderlist funktionen:

AppName: test.exe    AppVer: 0.0.0.0    ModName: msvcrt.dll
ModVer: 7.0.2600.0    Offset: 0002f548

Har prøvet på to computere, og med samme resultat.
Avatar billede tchami Nybegynder
23. oktober 2003 - 19:49 #13
Hmm, hvis jeg istedet for at køre den inde fra Dev-C++ (ved at trykke F9 - Compile & Run) kører den fra en dosprompt kan den godt udskrive listen, men kun to gange.

Output bliver:

**********Show grade list*************
Student: Bent  Grade: 3
Student: Hans  Grade: 5
Student: Lise  Grade: 6
Student: Lone  Grade: 7
Student: Inger  Grade: 8
Student: Bo    Grade: 9
Student: Else  Grade: 10
Student: Atli  Grade: 11
Student: Jens  Grade: 13
Student: <null>  Grade: 0
****************************************

Det er fuldstændig lost nu..
Avatar billede tchami Nybegynder
23. oktober 2003 - 19:50 #14
100 point mere for en løsning.
Avatar billede arne_v Ekspert
23. oktober 2003 - 19:54 #15
Du har stadigvæk:
  remaining->next = NULL;
fjernet ?

Den har jeg med !
Avatar billede arne_v Ekspert
23. oktober 2003 - 20:06 #16
Skulle jeg prøve at smide min version op for download ?
Avatar billede tchami Nybegynder
23. oktober 2003 - 20:10 #17
Hvis jeg tager remaining->next = NULL; med, får jeg samme output som dig, men kan kun se listen én gang. Hvis jeg vil se den igen får jeg en application error.

Jeg kan hverken se listen fra en dos prompt eller dev-c++, der får jeg en application error. Det "virker" kun når jeg dobbeltklikker på .exe filen.
Avatar billede tchami Nybegynder
23. oktober 2003 - 20:11 #18
det må du meget gerne..
Avatar billede arne_v Ekspert
23. oktober 2003 - 20:27 #19
http://www.vajhoej.dk/arne/eksperten/TEMP/

source + EXE med gcc + EXE med msvc
Avatar billede tchami Nybegynder
23. oktober 2003 - 22:48 #20
msvc versionen virker fint, men gcc versionen crasher hvis jeg prøver at vise listen to gange i træk.

Er det i øvrigt ikke en c++ fil du har compilet? Min er ren C.
Avatar billede arne_v Ekspert
23. oktober 2003 - 22:53 #21
Meget mystisk.

Det gør den ikke hos mig.

Jo - jeg compilede den som C++ - og den compiler også fint som C. Men
den virker stadig hos mig.

Hvad operativ system kører du ?
Avatar billede tchami Nybegynder
23. oktober 2003 - 22:59 #22
Windows XP pro.

Jeg har prøvet både på min stationære og bærbare, men med samme resultat (samme OS i øvrigt).
Avatar billede arne_v Ekspert
23. oktober 2003 - 23:09 #23
Mystisk.

Altså koden er ikke for køn fordi den allokerer memory som den aldrig frigør.

Men jeg kan ike forstå at den skulle crashe allerede på 2. gennemløb.
Avatar billede tchami Nybegynder
23. oktober 2003 - 23:14 #24
Næh, heller ikke mig.

Har du et forslag til hvordan jeg kan gøre koden pænere så?
Avatar billede arne_v Ekspert
23. oktober 2003 - 23:17 #25
Du bør jo få alt det malloc'ede memory free'ed igen, når det ikke længere skal bruges.

Men måske var det vigtigere at få dette mysterium afklaret.
Avatar billede arne_v Ekspert
23. oktober 2003 - 23:17 #26
Kan du poste et screen dump af en kørsel med min z_gcc.exe ?
Avatar billede tchami Nybegynder
23. oktober 2003 - 23:25 #27
Det kan du selvfølgelig have ret i.

Jeg har smidt et dump her: http://tchami.com/dump.jpg
Avatar billede arne_v Ekspert
23. oktober 2003 - 23:42 #28
Prøv med den her kode:

    // Split list in two
fprintf(stderr,"start while\n");
    while (node != NULL){
fprintf(stderr,"i=%d\n",i);
        if (i == 0){
            head = (Node*)malloc(sizeof(Node));
fprintf(stderr,"head=%p\n",head);
            head->name = node->name;
            head->grade = node->grade;
            head->next = NULL;
        }
        else {
            remaining = (Node*)malloc(sizeof(node));
fprintf(stderr,"remaining=%p\n",remaining);
            if (i == 1) first = remaining;
            remaining->name = node->name;
            remaining->grade = node->grade;
            remaining->next = NULL;
            if(parent != NULL) parent->next = remaining;
            parent = remaining;
        }
        node = node->next;
        i++;
    }
fprintf(stderr,"end while\n");
Avatar billede arne_v Ekspert
23. oktober 2003 - 23:43 #29
Den må vise lidt om hvor det går galt.
Avatar billede tchami Nybegynder
24. oktober 2003 - 00:07 #30
Har taget et nyt dump: http://tchami.com/dump_2.jpg

Som det kan ses bliver listen udskrevet én gang, men anden gang crasher det.

I øvrigt, mange MANGE tak fordi du gider hjælpe.
Avatar billede arne_v Ekspert
24. oktober 2003 - 00:28 #31
Prøv og højreklik på C:\WINNT\system32\msvcrt.dll
og vælg properties og version.

Min siger 6.1.8924.0 - hvad siger din ?
Avatar billede tchami Nybegynder
24. oktober 2003 - 00:32 #32
Den siger 7.0.2600.0
Avatar billede brilleaben Nybegynder
24. oktober 2003 - 10:16 #33
Vildt gæt ...  Students arrayet er defineret inde i start list funktionen.
Arrayet bliver allokeret på stack'en - ikke på en heap. Dvs. når du initializerer
de enkelte nodes sætter du "node->name" til et navn der er allokeret på
stacken. Når funktionen exiter umyndiggøres arrayet på stacken.  Navnene bliver
derved overskrevet når de andre funktioner bruger stacken.
Der er umiddelbart to måder at løse det på.

1) Erklær arrayet som "static"  (static Node student[10]={ ... })

2) Flyt Node student array'et ud som et globalt array - altså, ud af
funktionen.

Er blot et vildt gæt ...
Avatar billede brilleaben Nybegynder
24. oktober 2003 - 10:20 #34
... men derudover virker arne_v's version upåklageligt under gcc  :-)
Avatar billede tchami Nybegynder
24. oktober 2003 - 11:00 #35
tak for forslaget, men det virker ikke.

Selvfølgelig vil jeg meget gerne ha' løst problemet, men er der ikke en der har et forslag til en anden måde at gøre det på?
Avatar billede tchami Nybegynder
24. oktober 2003 - 12:15 #36
Så har jeg fundet fejlen..

Det var tydeligt at det var en fejl, MEN den var ualmindelig svær at finde.

Fejlen var denne linie:
remaining = (Node*)malloc(sizeof(node));

der selvfølgelig skulle ha' set således ud:
remaining = (Node*)malloc(sizeof(Node));

Bemærk det store N i sizeof(Node)

Så kan jeg lære det ka' jeg :)

Smider du et svar Arne?
Avatar billede arne_v Ekspert
24. oktober 2003 - 14:09 #37
Ah den var giftig !
Avatar billede arne_v Ekspert
24. oktober 2003 - 14:10 #38
Med hensyn til stack/heap så er students ganske vist allokeret
på stak men jeg vil formode at streng konstanterne er allokeret
i heap - og det er jo kun dem vi bevarer hen over kald.
Avatar billede tchami Nybegynder
25. oktober 2003 - 17:56 #39
Btw, i funktionen makestartlist som du hjalp mig med at lave er følgende to linier:

if (i>0) parent -> next = node;
parent = node;

Uden dem virker den ikke som den skal, men jeg kan ikke se hvorfor de skal være der, parent bliver jo ikke brugt til noget nogen steder. Kan du forklare det?
Avatar billede arne_v Ekspert
25. oktober 2003 - 18:06 #40
Det er de linier som sørger for at next peger på næste element.

if(i>0)                  hvis ikke første (d.v.s. at der er en foregående)
parent -> next = node;  sæt foregående's next til at pege på nuværende
parent = node;          sæt foregående til nuværende (for næste gennemløb)
Avatar billede tchami Nybegynder
25. oktober 2003 - 18:16 #41
Jeg fik vist formuleret mig lidt dårligt. Jeg forstår godt logikken i det, men jeg kan ikke se hvorfor parent bruges, for de to linier ændrer jo kun på hvad parent peger på og har ingen betydning for hvad node peger på.

Skal det forstås sådan at uden de to linier ville man ikke kunne "pushe" et nyt element ind foran det man netop har indsat?
Avatar billede arne_v Ekspert
25. oktober 2003 - 18:24 #42
parent peger jo på det der var node i foregående gennemløb og derfor ændrer
vi på det foregående element
Avatar billede arne_v Ekspert
25. oktober 2003 - 18:25 #43
første gemmenløb:

{ name="A", grade=1, next=NULL }

andet gennemløb før de 2 linier:

{ name="A", grade=1, next=NULL }
{ name="B", grade=2, next=NULL }

andet gennemløb efter de 2 linier:

{ name="A", grade=1, next=addressen på næste element }
{ name="B", grade=2, next=NULL }
Avatar billede tchami Nybegynder
25. oktober 2003 - 19:48 #44
Ahaa, nu forstår jeg.

Takker mange gange.
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester