简体   繁体   English

双链表中的常量结构在C中被修改

[英]Const structure in doubly linked list is being modified in C

I'm dealing with doubly linked lists and came an issue I'm not working around. 我正在处理双向链表,但出现了一个我没有解决的问题。 To illustrate it better, here's is the code before I say what the issue is. 为了更好地说明问题,在我说出问题所在之前,这里是代码。

Dblist.h 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 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 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;
}

Don't care about the malloc.h, it is small utility I'm using to ensure correct memory usgae 不在乎malloc.h,这是我用来确保内存usgae正确的小实用程序

So the problem is the interval variable comes from getInterval(const dblist *) , I want it to hold only a part of the initial list when either popBack or popFront has been applied. 所以问题是间隔变量来自getInterval(const dblist *) ,我希望在应用popBackpopFront时,它仅保留初始列表的一部分。

The problem is that if I make modifications to getInterval , it is influencing the values of pdbListe . 问题是,如果我对getInterval进行修改,则会影响pdbListe的值。 For example try to modify getInterval like this (try to comment those lines as illustrated below): 例如,尝试像这样修改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;
}

From there one can see that not only the result returned by getInterval (in this case the interval variable in main.c) but also the pdbListe variable which by essence should never be modified! 从那里可以看到,不仅是getInterval返回的结果(在本例中为main.c中的interval变量),而且还有pdbListe变量,从本质上讲,永远不要修改它!

What can I do to work around this? 我该怎么办才能解决此问题? I want pdbListe to remain as such and never be affected by what getInterval is doing. 我希望pdbListe保持原样,并且永远不受getInterval在做什么的影响。

If you want getRange to return a sublist, while the original list remains unmodified, then you need to modify how you terminate (put endpoints on) your list. 如果希望getRange返回一个子列表,而原始列表保持不变,则需要修改终止列表的方式(将端点放到列表上)。 You will need to stop using NULL as an end marker and use comparison to the first/last element pointers instead. 您将需要停止使用NULL作为结束标记,而改为使用与第一个/最后一个元素指针的比较。 For example: 例如:

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

Note the e != list->last , not e != NULL . 注意e != list->last ,而不是e != NULL

That way, you can make a sublist by constructing a dblist with new start/end points. 这样,您可以通过构造具有新起点/终点的dblist来创建子列表。 It no longer requires any modification to the underlying links (next and prev). 它不再需要对基础链接(下一个和上一个)进行任何修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM