2010-12-12 92 views
0

我正在處理雙向鏈表,並且遇到了一個我沒有解決的問題。爲了更好地說明這一點,下面是代碼,然後再說明問題所在。在雙向鏈表中的Const結構正在修改中C

Dblist.h

# Ifndef CGI_DBLIST_H 
# Define CGI_DBLIST_H 
# Include "malloc.h" 
/* Structure represantative an element of the list. */

typedef struct elem 
{ 
    int value; 
    struct elem * prev; 
    struct elem * next; 
} Elem; 

/* Structure access to the list. */

typedef struct 
{ 
    elem * first; 
    elem * last; 
} dblist; 

# ifdef __cplusplus 
extern "C" { 
# Endif 
    void Init (dblist * l);     /* Initialize the list */ 
    void pushback (dblist * s, int val);  /* Add a value at end */ 
    void PushFront (dblist * l, int val);  /* Add a value at start */ 
    int PopBack (dblist * l);     /* Remove value at end */ 
    int PopFront (dblist * l);     /* Remove value at start */ 
    void View (dblist l);      /* Display whole list */ 
    void ViewReverse (dblist l);    /* Display all reversed */ 
    void Clear (dblist * l);     /* discard list   */ 
    dblist getInterval (dblist const * s); 

    #ifdef __cplusplus 
    } 
    #endif 

    #endif /* CGI_DBLIST_H */ 

Dblist.c

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

#include "dblist.h" 
#include "malloc.h" 

void Init (dblist * l) 
{ 
    l-> first = NULL; 
    l-> last = NULL; 
} 

void pushback (dblist * s, int val) 
{ 
    elem * n = malloc (sizeof (elem)); 
    if (! n) exit (EXIT_FAILURE); 
    n-> value = val; 
    n-> prev = l-> last; 
    n-> next = NULL; 
    if (s-> last) s-> last-> next = n; 
    else s-> first = n; 
    l-> last = n; 
} 

void PushFront(dblist *l, int val) 
{ 
    elem *n = malloc(sizeof(elem)); 
    if(!n) exit(EXIT_FAILURE); 
    n->value = val; 
    n->next = l->first; 
    n->prev = NULL; 
    if(l->first) l->first->prev = n; 
    else l->last = n; 
    l->first = n; 
} 

int PopBack(dblist *l) 
{ 
    int val; 
    elem *tmp = l->last; 
    if(!tmp) return -1; 
    val = tmp->value; 
    l->last = tmp->prev; 
    if(l->last) l->last->next = NULL; 
    else l->first = NULL; 
    free(tmp); 
    return val; 
} 

int popFront(dblist* l) 
{ 
    int val; 
    elem *tmp = l->first; 
    if(!tmp) return -1; 
    val = tmp->value; 
    l->first = tmp->next; 
    //if(l->first)l->first->prev = NULL; 
    //else l->last = NULL; 
    //free(tmp); 
    return val; 
} 

dblist getInterval (dblist const * s) 
{ 
    dblist* intervals = NULL; 
    memmove(&intervals, &l, sizeof(l)); 
    if(intervals->first)intervals->first->prev = NULL; 
    else intervals->last = NULL; 

    return *intervals; 
} 

void View (dblist l) 
{ 
    elem *pelem = l.first; 
    while (Pelem) 
    { 
     printf ("% d \ n", pelem-> value); 
     pelem = pelem-> next; 
    } 
} 

void ViewReverse (dblist l) 
{ 
    elem* test = l.last; 

    while (test) 
    { 
     printf("% d \ n", test-> value); 
     test = test-> prev; 
    } 
} 

void Clear (dblist * l) 
{ 
    elem *tmp; 
    elem *pelem = l->first; 
    while(pelem) 
    { 
     tmp = pelem; 
     pelem = pelem->next; 
     free(tmp); 
    } 
    l->first = NULL; 
    l->last = NULL; 
} 

的main.c

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

#include "dblist.h" 

int main() 
{ 
    dblist pdbListe * = malloc (sizeof (dblist)); 
    dblist interval; 

    Init (pdbListe); 
    printf ("Pushin In The gains list\n"); 
    PushFront (pdbListe, 10); 
    Pushback (pdbListe, 20); 
    Pushback (pdbListe, 40); 
    PushFront (pdbListe, 23); 
    PushFront (pdbListe, 70); 
    PushFront (pdbListe, 54); 

    printf ("Viewing the list:\n"); 
    View (pdbListe *); 
    puts ("--------------"); 

    printf ("poping front capital gains from The Stack:\n"); 
    printf ("% d\n", PopFront (pdbListe)); 
    printf ("% d\n", PopFront (pdbListe)); 
    // Printf ("% d\n", PopBack (pdbListe)); 
    puts ("--------------"); 

    printf ("Viewing the list after pop front:\n"); 
    View (pdbListe *); 
    puts ("--------------"); 
    printf ("this is pdbListe:% p\n", pdbListe); 
    printf ("this is interval:% p\n", & interval); 

    interval = getInterval (pdbListe); 
    printf ("Viewing the interval\n"); 
    ViewReverse (interval); 
    printf ("first element is:% d\n", interval.first-> value); 
    printf ("last element is:% d\n", interval.last-> value); 
    puts ("--------------"); 

    printf ("Reverse Viewing the list after pop front:\n"); 
    ViewReverse (pdbListe *); // ISSUE HERE: it should print 6 elements not 4 
    puts ("--------------"); 

    printf ("this is pdbListe:% p\n", pdbListe); 
    printf ("this is interval:% p\n", & interval); 
    printf ("sizeof pdbListe% d\n", sizeof (pdbListe)); 
    printf ("sizeof interval% d\n", sizeof (interval)); 

    printf ("Pushing back a value in The List:\n"); 
    Pushback (pdbListe, 30); 

    printf ("Viewing the list after push back:\n"); 
    View (pdbListe *); 
    puts ("--------------"); 

    printf ("In The Front popping list:\n"); 
    printf ("% d\n", PopFront (pdbListe)); 
    printf ("% d\n", PopFront (pdbListe)); 
    puts ("--------------"); 

    printf ("Viewing the list after pop front:\n"); 
    View (pdbListe *); 
    puts ("--------------"); 
    printf ("Clearing the list\n"); 
    Clear (pdbListe); 

    printf ("Freeing the list\n"); 
    free (pdbListe); 

    system ("PAUSE"); 
    return 0; 
} 

不在乎malloc.h,它是我用來確保正確內存usga的小工具

所以問題是間隔變量來自getInterval(const dblist *),我希望它只保留一部分當popBackpopFront已被應用時的初始列表。

問題是如果我對getInterval進行修改,它會影響pdbListe的值。例如嘗試修改getInterval這樣的(嘗試如下圖所示評論那些行):

dblist getInterval(const dblist* l) { 
    dblist* intervals = NULL; 
    memmove(&intervals, &l, sizeof(l)); 
    //if(intervals->first)intervals->first->prev = NULL; 
    //else intervals->last = NULL; 

    return *intervals; 
} 

從那裏可以看出,不僅通過結果返回getInterval(在這種情況下main.c中的間隔可變)而且也是pdbListe變量,它本質上不應該被修改!

我能做些什麼來解決這個問題?我希望pdbListe保持原樣,不會受到getInterval正在做的事情的影響。

+0

對不起,正確的句子是:「從那裏可以看出,不僅getRange返回的結果(在本例中是main.c中的range變量),而且還有pdbListe變量正在被修改,這本質上不應該是修改!! – CHouse 2010-12-12 19:05:36

+0

有兩件事:你的代碼甚至沒有編譯,因爲一些函數接受一個名字爲「s」的參數,但是試圖使用一個名爲「l」的未聲明變量(當它們表示「s」時)第二,爲什麼你用memmove來複制單個指針?你是否想要複製「l」*指向*的東西? – zwol 2010-12-12 19:13:00

+0

可能代碼沒有編譯,我爲此道歉。花費了大量的編輯來使代碼可讀,所以可能會出現錯誤,但我相信我沒有改變邏輯。那個memcopy是爲了好玩!你可以使用assigment運算符(=),它會很好,在slig後HT代碼修改!謝謝 – CHouse 2010-12-13 00:30:55

回答

0

如果你想要getRange返回一個子列表,而原始列表保持未修改,那麼你需要修改你如何終止(放在端點上)你的列表。您將需要停止使用NULL作爲結束標記,並使用與第一個/最後一個元素指針的比較來代替。例如:

void printList(dblist *list) { 
    for (elem *e = list->first; e != list->last; e = e->next) { 
    printf("%d ", e->value); 
    } 
} 

e != list->last,不e != NULL

通過這種方式,您可以通過構建具有新的開始/結束點的dblist來創建子列表。它不再需要對底層鏈接進行任何修改(next和prev)。

+0

蘭德爾,謝謝你指出。事實上,正如我寫的,當我使用NULL作爲列表端點的值時,行爲發生了變化。這正是我在提出評論getRange()[now getInterval()]的一部分時提到的。我注意到當我在範圍[interval]列表上運行ViewReverse()函數時,它會打印出原來的列表。如果我不明白你的建議,請賜教getRange()[getInterval()] FUNCTION的新構造。謝謝 – CHouse 2010-12-13 00:36:57

+0

@Randall:通過考慮你的建議,我修改了getRange()[getInterval()]函數,並得到了一些有趣的結果:原始列表未被修改,但新列表仍包含一些元素當我應用ViewReverse()[尚未與您展示的printList()結構一起使用時,我會確保新列表位於範圍內的邊界內。這裏是:如果(範圍 - >第一)range-> first-> prev = 1-> first-> prev; else ranges-> last = l-> last; – CHouse 2010-12-13 00:57:56

+0

@Randall:其實你的回答已經解決了我的問題!但如果你能考慮到我的最後一個問題,並研究它,它將會有更大的幫助。最好的問候 – CHouse 2010-12-13 01:10:37