-2
#include<stdio.h>

struct node {
    int info;
    struct node *next;
};

typedef struct node *nodeptr;
nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

void freenode(nodeptr p)
{
    free(p);
}


int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

    p = getnode();
    q = getnode();
    q = start;
    p = end;

    for (i = 0; i < 6; i++) {
        printf("enter value");
        scanf("%d", &r);
        p = getnode();
        p->info = r;

        q->next = p;

        q = q->next;

    }

    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    scanf("%d", &a);
    end = getnode();
    end->info = a;
    end->next = NULL;

    for (q = start; q->next != NULL; q = q->next)
        ;

    q->next = end;
    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    for (q = start; q->next->next != NULL; q = q->next)
        ;

    freenode(q->next);
    q->next = NULL;
    q = start;

    while (q->next != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }


    return 0;
}

在这个程序中创建了 alist 并在最后插入了一个元素在这个元素被删除但列表没有正确显示只有最后两个元素被显示请帮助以显示删除元素的整个列表

4

2 回答 2

4

有很多错误,不幸的是。正如 WhozCraig 所说,关于这个主题还有很多其他帖子,所以你应该在发帖前多搜索一下。但是既然你有,让我们一起来解决一些问题。

nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

在这里,您要声明大量全局变量,其中大多数名称都不好。是什么i?是什么p?是什么q?再往下,您重新声明具有相同名称的变量。有的类型相同,有的类型不同。这使您很难知道您引用的是哪个变量。

一般来说,避免使用全局变量并选择描述性名称。在这种情况下,您可以摆脱i,pq

此外,您永远不会初始化plist任何东西;您应该养成将变量初始化为一些合理的默认值的习惯。在这种情况下,NULL可能是合适的,但由于您根本不使用该变量,因此可以将其删除。

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

这很好,但是在 C 中,您不应该将结果malloc转换为特定类型,因为这被认为是错误的形式,并且可能导致微妙且难以检测的错误。直接指定return frommalloc即可。

其次,您永远不会检查以确保malloc成功。当然,在您的简单程序中它不太可能会失败,但您应该养成检查可能失败的函数的返回值的习惯。

而且您可能应该将分配的内存初始化为某个默认值,因为返回给您的内存malloc充满了垃圾。在这种情况下,这样的事情似乎很合适:

if(p) /* only if we allocated memory. */
    memset(p, 0, sizeof(struct node));

有时您可以跳过此操作,但清除内存是一种明智的默认做法。

void freenode(nodeptr p)
{
    free(p);
}

这也很好,但您应该考虑在调用之前验证它p不是 NULL free。同样,这归结为健壮性,这是一个养成的好习惯。

int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

同样,这里我们有很多未初始化的变量,但至少其中一些名称要好一些。但请注意会发生什么:

您声明一个名为itype的变量int。但是您已经声明了一个名为ithat 的全局变量,其类型为nodeptr。所以现在,局部作用域中的变量(int隐藏(即隐藏它)全局变量。所以里面main的名字i指的是int。当有人阅读您的程序时,这只会增加混乱。

    p = getnode();
    q = getnode();

好的...所以,在这里您分配两个新节点并生成pq指向这些节点。到目前为止,一切都很好。

    q = start;
    p = end;

哎呀...现在这是一个问题。我们现在 makepq指向任何地方startend分别指向。

这些指向哪里?谁知道。两者startend都被统一化了,所以它们可以指向任何东西。从这一点开始,您的程序表现出未定义的行为:这意味着任何事情都可能发生。在这种情况下,它很可能会崩溃。

不幸的是,从这里开始,事情变得更加混乱。与其试图解释一切,我只会给出一些一般性的评论。

    for (i = 0; i < 6; i++) {
        printf("enter value");
        scanf("%d", &r);
        p = getnode();
        p->info = r;

        q->next = p;

        q = q->next;    
    }

这个循环应该读取 6 个整数并将它们放入我们的链表中。这似乎是一件简单的事情,但也有问题。

首先,你永远不会检查返回scanf来知道输入操作是否成功。正如我之前所说,您应该始终检查可能失败的函数的返回值并相应地处理失败。但在这种情况下,让我们忽略该规则。

一个大问题是q指向内存中的随机位置。所以我们处于未定义的行为领域。

另一个大问题是有两种情况需要考虑:当列表为空时(即我们第一次向列表中添加数字时i == 0)和列表不为空时(即每隔一次)。这两种情况下的行为不同。当i == 0我们不能盲目地设置q->next时,因为即使q不指向随机位置,从概念上讲,也不会q像这里使用的那样。

我们需要的是一些额外的逻辑:如果这是我们创建的第一个节点,则设置q为指向该节点。否则,设置q->next为该节点,然后执行q = q->next.

另请注意,您从未在任何地方设置p->next,这将导致您的列表不会以 NULL 结尾(您在此处和其他循环中依赖的东西)。中的memset修复解决了getnode这个问题,但通常您应该确保如果您的代码需要特定的行为(“未链接节点的next指针指向 NULL;列表以 NULL 结尾”),您应该有代码来确保该行为。

    q = start;

同样,在这里,我们重新q设置指向尚未初始化并指向垃圾的指向start

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

这是一个经典的打印循环。就其本身而言,这里没有错,尽管我认为从文体上讲,这些括号q->next是多余的,并且使阅读代码比必须的要困难一些。我的指导方针是仅在需要覆盖 C 的默认评估顺序时添加括号,或者当括号有助于在视觉上向读者解释如何在精神上解析代码时在他的脑海中对表达式进行分组。

    scanf("%d", &a);
    end = getnode();
    end->info = a;
    end->next = NULL;

这很好,除了 的错误检查问题scanf,尽管您不提示用户输入数字。但是您正确而明确地end->next指出NULL哪个很棒。

    for (q = start; q->next != NULL; q = q->next)
        ;

同样,这里的问题是qstart不幸的是,它仍然指向垃圾。

    q->next = end;
    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

这是您第二次必须键入此代码来打印列表。通常,您应该避免代码重复。如果您发现在多个地方需要特定代码块,则将其拆分为一个函数并使用该函数是有意义的。这使得理解和维护代码更容易。

    for (q = start; q->next->next != NULL; q = q->next)
        ;

由于这个位,这个循环很难理解q->next->next。问问自己“如果我正在阅读这篇文章,我是否立即确定它q->next永远不会为 NULL?” 如果你不是,那么你真的应该重写这个循环。

    freenode(q->next);
    q->next = NULL;
    q = start;

再次q指出,start哪个是单化的。但是,嘿,如果我们还没有坠毁... ;)

    while (q->next != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

再一次......这应该是一个真正的功能。

    return 0;
}

为了更好的实现,我建议您参考这里提出的许多其他问题之一(只需搜索“链表删除”。Khalid Waseem 在这个问题中的实现也可能会有所帮助,但它的文档记录并不多,所以你会有仔细研究和分析代码以确保您理解它。

于 2013-09-02T18:54:15.097 回答
0

请参阅下面的实现以获得更好的理解。

struct node {
    int info;
    struct node *next;
};

typedef struct node node;

//Function to print a given single linked list.
void print_list(node *start)
{
    //Check if the given list is empty. 
    if(start == NULL)
            printf("List Empty!!!");
    else
    {
            printf("Current List:");
            //Visit each node one by one 
            while(start != NULL)
            {
                    printf(" %d", start->info);
                    start = start->next;
            }
    }
}
//Function to insert a node at end of single linked list with given data 
node* insert_at_end(node *start, int data)
{
    node *ptr;

    //Create a new node and assign memory using malloc  
    node* new_node = (node*)malloc(sizeof(node));
    if(new_node != NULL)
    {
        //Initialize new node with data.
        new_node->info = data;
        new_node->next = NULL;
    }
    else
    {   //Panic
        printf("\nMemory not allocated. Insertion failed!!!");
        return start;
    }

    //If input list is empty. then new_node becomes the first node of link list.
    if(start == NULL)
            return new_node;
    else
    {
            //travel to the last node of list
            ptr = start;
            while(ptr->next != NULL)
                    ptr = ptr->next;
            //Attach the newly created node at end of list.
            ptr->next = new_node;
            return start;
    }
}

//Delete a node from the end of a Single linked list
node* delete_at_end(node *start)
{
    node *ptr;

    //If input list is empty. nothing to delete just return. 
    if(start == NULL)
            return NULL;
    //Just one node in the given linked list.
    else if(start->next == NULL)
    {
            //Free the memory assigned to the node.
            free(start);
            return NULL;
    }
    else
    {       //Travel to the second last node of the linked list.
            ptr = start;
            while(ptr->next->next != NULL)
                    ptr = ptr->next;
            //free the last node. 
            free(ptr->next);
            ptr->next = NULL;
            return start;
    }
}

int main()
{
    int i, data;
    node *Head_node = NULL;

    for(i = 1; i<=5 ; i++)
    {
            printf("\nEnter node %d :", i);
            scanf("%d", &data);

            // Insert at End
            Head_node = insert_at_end(Head_node, data);

            // Print current List
            print_list(Head_node);
    }

    for(i = 5; i>=1 ; i--)
    {
            printf("\nDeleting node %d :\n", i);

            // Delete at End
            Head_node = delete_at_end(Head_node);

            // Print current List
            print_list(Head_node);
    }

    return 0;
}
于 2013-09-02T19:52:14.900 回答