2010-12-12 91 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