0

问题解决了:)

我希望你能帮助解释我做错了什么。

提前致谢!

代码:

#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

4

2 回答 2

0

我通常尝试在插入元素之前将头部和尾部保持为 NULL,而不是尝试在整个地方检测空节点。包括我使用的一个非常简单的链表的示例。请注意,此版本适用于微控制器,因此我 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);  
}

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

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

最后,它可能无法在 print 函数中正确迭代的原因是您在尾部而不是头部启动打印迭代器。

于 2012-05-05T23:04:48.043 回答
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;
}

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

头 - 尾

头 - 第一 - 尾巴

头部 - 第 2 - 第 1 - 尾巴

...

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

至于你的

char * tmpBuf = buf;

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

这条线

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

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

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

这个 malloc 实际上为 10 个字符的数组腾出了空间,并将数组的地址保存在节点数据字段中。如果没有第二个 malloc,您永远不会为实际数组腾出空间。当您第一次学习数据结构时,我可能会建议您使用整数作为您的数据类型。让您从正在学习的实际数据结构的工作中分心的陷阱更少。

于 2012-05-05T23:33:16.547 回答