我的链接列表代码有什么问题?

时间:2012-05-05 22:46:16

标签: c linked-list

问题解决了:)

我希望你能解释一下我做错了什么。

提前致谢!

代码:

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

typedef struct node {
    char *data;
    struct node * previous;
    struct node * next;
} node, *nodePTR;

/* Insert into list */
void insert(char * buf, nodePTR tail) {
    nodePTR myNode;
    myNode = (node *)malloc(sizeof(node));

    myNode->data = malloc(sizeof(char) * 10);
    strcpy(myNode->data,buf);
    myNode->next = NULL;
    myNode->previous = tail;
    tail->next = myNode;
    //tail = tail->next;
}

void printlist(nodePTR head, int numElements) {
    nodePTR tmpNode;
    tmpNode = head;

    printf("\n\n");

    while(tmpNode!=NULL) {
        printf("Node data: %s\n", tmpNode->data);
        tmpNode = tmpNode->next;
    }
}

int main(void) {
    /* Variables */
    int numElements;
    int i;
    char buf[10];

    nodePTR head, tail;

    tail = (node *)malloc(sizeof(node));
    head = (node *)malloc(sizeof(node));

    tail->data = "EMPTY\0";
    tail->next = NULL;
    tail->previous = NULL;

    head = tail;

    printf("Please enter the number of elements:\n");
    scanf("%d", &numElements);

    /* Build the list */
    for(i = 0; i < numElements; i++) {
        printf("Please enter the data:");
        scanf("%s", buf);
        insert(buf, tail);
        tail = tail->next;
    }

    printlist(head, numElements);

    return 0;
}

这是我的输出:
请输入元素数量:
3
请输入数据:n1
请输入数据:n2
请输入数据:n3

节点数据:EMPTY
节点数据:n3

2 个答案:

答案 0 :(得分:0)

我通常会尝试将头部和尾部留空,直到插入一个元素,而不是尝试在整个地方检测到一个空节点。包含的是我使用的非常简单的链表的示例。请注意,此版本适用于微控制器,因此我malloc /释放列表函数之外的内存(有时来自预分配的节点池):

struct ListNodeStruct
{
  struct ListNodeStruct* Next;
  int Value;
};
typedef struct ListNodeStruct ListNode;

struct ListStruct
{
  ListNode* Head;
  ListNode* Tail;
  int Count;
};
typedef struct ListStruct List;

List CreateList()
//creates a new List
{
  List R;
  R.Head = NULL;
  R.Tail = NULL;
  R.Count = 0;
  return(R);
}

void ListInsertFirst(List* L, ListNode* V)
//insert the object at the start of the list
{
  V->Next = L->Head;
  L->Head = V;
  if (L->Count == 0)
    L->Tail = V;
  L->Count ++;
}

void ListInsertLast(List* L, ListNode* V)
//insert the object at the end of the list
{
  V->Next = NULL;
  if (L->Tail)
    L->Tail->Next = V;
  else
    L->Head = V;
  L->Tail = V;
  L->Count++;
}

ListNode* ListRemoveFirst(List* L)
//remove the first object in the list (no memory is freed)
{
  ListNode* R = L->Head;

  if (L->Head == NULL)
    return(R);

  L->Head = L->Head->Next;
  L->Count--;
  if (L->Count == 0)
    L->Tail = L->Head;
  return(R);  
}

特定于您的代码,当您将对象视为黑盒子时,可以避免一些问题,除了允许看到内部的功能。具体来说,主函数的开头以及第69行直接操作列表成员。我通常会尝试使用专门用于初始化对象的函数,因为在使用列表时,您必须在许多地方再次执行此操作。

在第54行,您将指向字符串文字的指针推入结构中。此指针仅在当前堆栈帧上有效,这意味着当函数退出此指针时,不再包含“EMPTY \ 0”。您应该调用malloc并将其存储在那里,并且不要忘记免费。另请注意,C自动为空终止字符串文字,因此您最后不需要\ 0。

最后,它可能无法在打印功能中正确迭代的原因是因为你在尾部而不是头部开始打印迭代器。

答案 1 :(得分:0)

好吧,我认为你的问题是你将所有节点都指向同一个缓冲区。您需要每次都复制该缓冲区。

myNode->data = buf;

只需将数据指向缓冲区的地址即可。然后,当你更新缓冲区时,地址保持不变但内容发生变化。所以一切都基本上指向相同的字符串。您需要将缓冲区的内容复制到一个新数组中并指向该数据。

当你循环添加节点时,这条线似乎也有问题:

head = head->next;

插入应该照顾它。

这是你的代码重新工作:

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

typedef struct node {
    char *data;
    struct node * previous;
    struct node * next;
} node, *nodePTR;

/* Insert into list */
void insert(char * buf, nodePTR head) {
    nodePTR myNode;
    myNode = (node *)malloc(sizeof(node));

    myNode->data = malloc(sizeof(char) * 10);
    strcpy(myNode->data,buf);
    myNode->next = head->next;
    myNode->previous = head;
    head->next = myNode;
}

void printlist(nodePTR head, int numElements) {
    nodePTR tmpNode;
    tmpNode = head;

    printf("\n\n");

    while(tmpNode!=NULL) {
        printf("Node data: %s\n", tmpNode->data);
        tmpNode = tmpNode->next;
    }
}

int main(void) {
    /* Variables */
    int numElements;
    int i;
    char buf[10];

    nodePTR head, tail;

    tail = (node *)malloc(sizeof(node));
    head = (node *)malloc(sizeof(node));

    tail->data = "EMPTY\0";
    tail->next = NULL;
    tail->previous = NULL;

    head = tail;

    printf("Please enter the number of elements:\n");
    //scanf("%d", &numElements);
    numElements=3;

    /* Build the list */
    for(i = 0; i < numElements; i++) {
        printf("Please enter the data:");
        buf[0] = 60 + i;
        buf[1] = 0;
        insert(buf, head);
    }

    printlist(head, numElements);

    return 0;
}

我摆脱了输入提示,所以我可以让它在键盘上工作,但想法是一样的。此外,我想我不小心摆脱了跟踪尾巴。这将在头部之后插入东西所以它将开始:

HEAD - TAIL

HEAD - 1st - TAIL

HEAD - 2nd - 1st - TAIL

...

其中2nd是您插入的第二个元素。

至于你的

char * tmpBuf = buf;

问题是tmpBuf在堆栈上,而仍然指向与buf相同的地址。你需要用malloc分配一个新的缓冲区(或者在评论中按照我的比喻建造一个新的房子)。

这一行

myNode = (node *)malloc(sizeof(node));

为您在节点结构中定义的内容创建足够的空间。在您的情况下, 指针 对于字符数组,下一个节点和前一个节点。所有你有空间的是一系列字符的地址。实际上,节点中的字符数组实际上没有空间。

myNode->data = malloc(sizeof(char) * 10);

这个malloc实际上为10个字符的数组腾出空间,并在节点数据字段中保存数组的地址。如果没有第二个malloc,你永远不会为实际阵列腾出空间。当您第一次学习数据结构时,我可能会建议您使用整数作为数据类型。从您正在学习的实际数据结构的工作中分散注意力的可能性较小。