【问题标题】:Singly Linked List - C单链表 - C
【发布时间】:2011-07-27 15:19:19
【问题描述】:

我有一个关于单链表的非常简短的问题,我在其他问题中找不到答案。

这是我的代码:

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

void add(int data);
void printList();

struct node
{
    int data;
    struct node * link;
};

struct node * head = NULL;

main()
{
    char c; 

    while ((c = getchar()) != 'q')
    {
        if (c == 'a')
        {
            int temp;

            printf("data: ");
            scanf("%d", &temp);

            add(temp);
        }

        if (c == 'p')
            printList();
    }
}

void add(int data)
{
    struct node * temp = (struct node *) malloc(sizeof(struct node));

    if (temp == NULL)
        fprintf(stderr, "error");

    temp->link = head;
    temp->data = data;
    head = temp;
}

void printList()
{
    struct node * temp = (struct node *) malloc(sizeof(struct node));

    if (temp == NULL)
        fprintf(stderr, "error");

    temp = head;

    while (temp != NULL)
    {
        printf("%d", temp->data);
        temp = temp->link;
    }
}

现在,有人告诉我,我需要在我的 add 函数中创建一个函数或一个场景,如果正在创建一个新列表,它会做一些不同的事情。换句话说,当列表为空并且第一个元素被添加到其中时,它需要与填充列表在前面接收另一个节点时不同。我在网上找到了这样的代码示例:

# // Adding a Node at the Beginning of the List  
#   
# void addBeg(int num)  
# {  
#    struct Node *temp;  
#   
#    temp=(struct Node *)malloc(sizeof(struct Node));  
#    temp->Data = num;  
#   
#    if (Head == NULL)  
#    {  
#       //List is Empty  
#       Head=temp;  
#       Head->Next=NULL;  
#    }  
#    else  
#    {  
#       temp->Next=Head;  
#       Head=temp;  
#    }  
# } 

如您所见,如果列表为空,则填充头节点。

我的代码工作正常,但我想知道在处理空头情况方面我是否忽略了一些东西。

非常感谢!

【问题讨论】:

  • 您的 add() 函数可以工作,但如果 malloc 失败,它会出现段错误。如果temp == NULL,你应该return。您也不需要在 print 中 malloc 一个新节点,只需使用指向 head 的指针就足够了。内存泄漏
  • 您的 printList 函数有一个错误:它 malloc 一个新的临时节点,然后立即用头指针覆盖 malloc 的指针,从而泄漏分配的节点。在这种情况下,分配是不必要的。

标签: c


【解决方案1】:

您的add() 函数根本没有问题。 head == NULL 不需要特殊处理的情况。

正如其他人所注意到的,您的错误检查不正确,因为您需要从函数返回以防malloc 失败。就目前而言,当tempNULL 时,您的add() 函数会尝试分配给*temp

您显示的经过这种特殊处理的代码是伪造的。当head == NULL 时,该代码中的else 子句运行良好。

【讨论】:

  • 有趣。谢谢!我觉得很奇怪我是如何在学校被教导分开做的。哦,好吧!
  • 好吧,所以我理解它的方式,我的代码很好。最好检查 null 的实例,否则,我的程序不应该产生任何意外故障吗?再次感谢大家!
  • @seyelent 如果要取消引用,您只需检查 NULL。如果您打算将可能为 NULL 的内容分配给指针,那么您不需要任何特殊处理。
  • "但除此之外,我的程序不应该产生任何意外故障吗?"好吧,请参阅问题的 cmets 以了解一些故障。
【解决方案2】:

您可以选择每次使用时检查 head 上的指针是否为 null,或者如果您以不同方式处理 head 节点,则可以假设它不为 null。

良好的礼仪假定您应该始终检查它,但如果您不检查并且不取消引用空指针,那么您的代码仍然可以工作。

【讨论】:

    【解决方案3】:

    因为您将始终运行该行(添加节点时)

    head = temp;
    

    添加节点后,您的头节点中将永远不会有 NULL 引用。这是因为您在上面验证了 (temp != null) temp 不是空指针。

    现在在搜索节点时,最好先检查头节点是否为空,然后再访问它(不)指向的任何字段。也许这就是“特殊条件”中的意思,并且注释与通常不需要的这种情况混在一起。

    【讨论】:

    • 嗯...除非 temp 是 NULL
    • 在这种情况下,代码将退出上面的四行。编码(如国际象棋)要求您同时关注本地事件和可能影响本地事件的远距离事件。
    【解决方案4】:

    如果你考虑addBeg if 分支:

    if (Head == NULL)  
    {  
       Head=temp;  
       Head->Next=NULL;  
    }  
    else  
    {  
       Head=temp;  
       temp->Next=Head;  
    }  
    

    您看到您将temp 分配给head,然后设置next 指针。 另一方面,您的实现是:

    temp->link = head;
    temp->data = data;
    head = temp;
    

    如果您跳过data 部分(以及在两种情况下都存在的head = temp),您将很容易看到它等同于第一个,因为

    temp->link = head;
    

    等同于:

    if (Head == NULL)  
    {  
       Head->Next=NULL;  
    }  
    else  
    {  
       temp->Next=Head;  
    }  
    

    【讨论】:

    • Head == NULL,Head-&gt;Next = NULL肯定会导致程序崩溃。
    • @larsmans:我太坏了!你是对的,我编辑了我的答案,推理仍然成立......
    猜你喜欢
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2010-11-08
    • 2011-03-11
    • 2016-06-15
    • 2011-01-19
    相关资源
    最近更新 更多