【问题标题】:Singly Linked List: newNode function doesn't point to next Node单链表:newNode 函数不指向下一个节点
【发布时间】:2019-05-19 04:32:55
【问题描述】:

我目前正在用 C 语言试验单链表。我写了一个 newNode 函数用于创建节点,printNodes 函数用于打印所有节点 - 如下所示:

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

struct Node 
{
  int data;
  struct Node *next;
}; 

void printNodes(struct Node *current_node)
{
  while(current_node != NULL)
  {
    printf("Node is: %d\n", current_node->data);
    current_node = current_node->next;
  }
}

int main()
{
  int number_1 = 2;
  int number_2 = 3;
  int number_3 = 4;

  struct Node *head;
  struct Node *second;
  struct Node *third;

  head = (struct Node*)malloc(sizeof(struct Node));  
  second = (struct Node*)malloc(sizeof(struct Node)); 
  third = (struct Node*)malloc(sizeof(struct Node));

  head->data = number_1;      
  head->next = second; 

  second->data = number_2;      
  second->next = third; 

  third->data = number_3;     
  third->next = NULL; 

  printNodes(head);

}

输出正确:

Node is: 2
Node is: 3 
Node is: 4

现在我想写一个函数newNode来创建一个新节点,我把我的代码改成这样:

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

struct Node 
{
    int data;
    struct Node *next;
};

struct Node *newNode(int number_x, struct Node *nextnode)
{
    struct Node *tmp_node;

    tmp_node = malloc(sizeof(struct Node));
    tmp_node->data = malloc(sizeof(struct Node));
    tmp_node->data = number_x;
    tmp_node->next = nextnode;

    return tmp_node;
}   

void printNodes(struct Node *current_node)
{
    while(current_node != NULL)
    {
        printf("Node is: %d\n", current_node->data);
        current_node = current_node->next;
    }
}

int main()
{
    int number_1 = 2;
    int number_2 = 3;
    int number_3 = 4;

    struct Node *head;
    struct Node *second;
    struct Node *third;

    head = newNode(number_1, second);
    second = newNode(number_2, third);
    third = newNode(number_3, NULL);

    printNodes(head);

}

编译后我首先得到这个警告信息:

test.c:16:20: warning: incompatible pointer to integer conversion 
assigning to 'int' from 'void *' [-Wint-conversion]
tmp_node->data = malloc(sizeof(struct Node));
               ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

输出如下所示:

Node is: 2

它只显示节点head,我猜next指向有问题 (例如head-&gt;next = second),但有什么问题?我无法解决这个问题。

谢谢

【问题讨论】:

  • 仅供参考,当你这样做时,问问自己secondmain 中的值是多少:head = newNode(number_1, second);?如果您的答案是“我不知道”,那么您与您的程序在同一页面上,因为它也不是。指针保存(恰好是地址)。如果没有正确分配它们(在这种情况下构建您的列表向后),您正在加载具有不确定值的结构next成员,稍后对其进行评估会调用未定义的行为 .关于您的错误,您为什么要为 int 数据成员分配内存地址?
  • 您的错误与问题无关,但这是一个问题,因为您正在泄漏内存 - tmp_node-&gt;dataint 并且不需要为其分配内存......尤其是作为你在后面的行覆盖它的内容
  • @WhozCraig second我猜没有值,它只是一个已初始化的节点,因为我希望 head 指向 secondwith 节点(如ex1).. 所以我猜 second 的输入是空的?
  • @s.r.换一种方式。如果我写int x; printf("%d\n", x);,你希望打印什么?这里唯一正确的答案是“我们不知道 x 是什么,所以我们不知道”。第二个代码列表中的 secondthird 指针也是如此。在您使用它们时,它们没有被赋予确定的值,因此将它们的值用作函数的输入是没有意义的。现在,考虑一下如果您使用与现在相同的调用(但顺序相反)向后(第三个,然后是第二个,然后是头部)构建节点会发生什么。想想吧。

标签: c linked-list int nodes singly-linked-list


【解决方案1】:

这里

tmp_node->data = malloc(sizeof(struct Node)); /* remove this statement */

datastruct Node 的成员,这是一个整数,为此您不必单独分配内存。你已经在这里分配了完整的结构

tmp_node = malloc(sizeof(struct Node)); /* this is enough */

这里也有

head = newNode(number_1, second);

second 是什么?应该用NULL 之类的来初始化

struct Node *second = NULL;

那么仅在newNode() 函数tmp_node-&gt;next 中分配了正确的值

tmp_node->next = nextnode; /* now nextnode contains NULL, that's correct */

或者你可以像下面这样

head = newNode(number_1, NULL);
second = newNode(number_2, head);
third = newNode(number_3, second);

然后在调用printNodes() 时传递third 而不是head。例如

printNodes(third);

示例代码:

struct Node  {
    int data;
    struct Node *next;
};

struct Node *newNode(int number_x, struct Node *nextnode) {
    struct Node *tmp_node;
    tmp_node = malloc(sizeof(struct Node));
    tmp_node->data = number_x;
    tmp_node->next = nextnode;
    return tmp_node;
}

void printNodes(struct Node *current_node) {
    while(current_node != NULL) {
        printf("Node is: %d\n", current_node->data);
        current_node = current_node->next;
    }
}

int main(void) {
    int number_1 = 2;
    int number_2 = 3;
    int number_3 = 4;

    struct Node *head = NULL;
    struct Node *second = NULL;
    struct Node *third = NULL;

    head = newNode(number_1, NULL);
    second = newNode(number_2, head);
    third = newNode(number_3, second);
    printNodes(third);
        return 0;
}

【讨论】:

  • 虽然您的回答指出了一个问题 - 它并没有回答所提出的问题
  • 感谢@ChrisTurner 的指点。我想它现在可以工作了。我的即时回复是关于 OP 关于malloc() 的警告信息。
【解决方案2】:

感谢@WhozCraig 的澄清。

正如他所提到的,second 节点不知道他的输入是什么。 为了分解它,如果你写这样的东西也会发生同样的情况: int num; printf("%d",num)

程序不知道输入是什么,因为没有初始化输入。

我的程序也发生了同样的事情,没有节点初始化,所以程序不知道next-node 在哪里。 但是如果我倒着写程序,程序现在确实理解了值是什么并且可以使用它:

    //use it backwards
    third = newNode(number_3, NULL);
    second = newNode(number_2, third);
    head = newNode(number_1, second);

现在,输出正确:

Node is: 2
Node is: 3
Node is: 4

感谢您的帮助, 干杯。

【讨论】:

    【解决方案3】:

    首先,您看到的警告(应被视为错误,仅供参考)与您的整体问题无关,但它仍然很重要。它既不合适,又会泄漏内存,并且具有测试意大利面条的模糊外观。万一你从来没有做过,一个老式的厨房技术来看看意大利面是否“完成”是从锅里拿出一根线,然后把它扔到墙上看它是否粘住。这段看似无关的代码看起来就是这样;就像你往墙上扔东西看它是否卡住了:

    这个:

    tmp_node->data = malloc(sizeof(struct Node)); // DELETE THIS
    

    根本不应该出现在你的代码中;接下来的行做了应该做的事情,即:

    tmp_node->data = number_x; // KEEP THIS
    

    连接链接列表

    虽然之前的谩骂令人担忧,但这并不是导致您无法正确排列列表的令人羡慕的立场。这本身就是一个问题。考虑以下几点:

    struct Node *head;      // indeterminate
    struct Node *second;    // indeterminate
    struct Node *third;     // indeterminate
    

    在前两个newNode 调用中,您将不确定的指针值传递给最终将成为新分配的节点next 的指针。这很重要。我颠倒构建顺序,您可以获得您所寻求的行为。

    third = newNode(number_3, NULL);    // third is set, next points to NULL
    second = newNode(number_2, third);  // second it set, next points to third
    head = newNode(number_1, second);   // head is set, next points to second
    

    显然,必须这样做并不理想,但只是了解事物的连接方式是一种方法。另一种方法是直接分配给下一个成员。例如:

    head = newNode(number_1, NULL); 
    head->next = newNode(number_2, NULL);
    head->next->next = newNode(number_3, NULL);
    

    这同样有效,但同样不理想。你真的想这样做来构建一个包含一百个节点的链表吗?

    正向链接链表

    一种非常简洁的方法来构建升序链表,而无需执行上述操作。它被称为正向链接,并利用了一个指向指针的指针,它最初指向头指针本身(最初为 NULL):

    struct Node *head = NULL;
    struct Node **pp = &head; // points to a pointer, initially the head pointer
    

    通过以上内容,我们可以将您想要的任意数量元素的列表链接在一起。一百 ?没问题:

    for (int i=1; i<=100; ++i)
    {
        // allocate a new node, storing the address at whatever pointer
        // is being addressed by the pointer-to-pointer pp. Initially it
        // will be the `head` pointer variable.
    
        *pp = malloc(sizeof **pp);
        (*pp)->data = i;
    
        // move pp to point to the next pointer of the node we just added
        pp = &(*pp)->next;
    }
    *pp = NULL; // terminate the list
    
    
    printNodes(head);
    

    这只是构建链表的一种方法。还有很多其他的(例如,在学校学习递归时,递归地进行并不少见)。但它可能是最简单的,几乎可以肯定是最快的。

    无论如何,这比我预期的要长,但我希望它有所帮助。

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 2013-07-26
      • 2014-12-13
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      相关资源
      最近更新 更多