指向指针的指针 - 链接列表混乱

时间:2016-11-05 21:01:31

标签: c pointers linked-list

我正在编写一个简单的C程序来管理定义如下的链接列表:

typedef struct node {
    int value;
    struct node *next;
} *List;

我查看了代码并且看起来没问题但是在打印结果时效果不佳。

我的主要评论问题:

int main(void) {
    List n = list_create(1);
    insert(n, 2);
    insert(n, 3);
    insert(n, 5);
    insert(n, 4);
    //something here does not work properly. It produces the following output:
    //Value: 1
    //Value: 2
    //Value: 3
    //Value: 4
    //where is value 5?
    print_list(n);
    delete(n, 3);
    print_list(n);
    return 0;
}

我不知道我在哪里销毁列表结构。如果你太善良,这些是我的调试功能。

List list_create(int value) {
    List new = malloc(sizeof(struct node));
    new->value = value;
    new->next = NULL;
    return new;
}

List new_node(int value, List next_node) {
    List new = malloc(sizeof(struct node));
    new->value = value;
    new->next = next_node;
    return new;
}

void print_list(List l) {
    List *aux;
    for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
        printf("Valor: %d\n", (*aux)->value);
}

void insert(List l, int value) {
    List *p;
    for (p = &l; (*p) != NULL; p = &((*p)->next))
        if ((*p)->value > value) {
            List tmp = *p;
            List new = new_node(value, tmp);
            *p = new;
            break;
        }
    *p = new_node(value, NULL);
}

void delete(List l, int value) {
    List *p;
    for (p = &l; (*p) != NULL; p = &((*p)->next))
        if ((*p)->value == value) {
            List del = (*p);
            (*p) = ((*p)->next);
            free(del);
            break;
        }
}

2 个答案:

答案 0 :(得分:2)

此代码(至少)有两个错误:

  1. 该行

    if((* p) - > value> value){

  2. 意味着如果你以1作为第一个值开始列表,然后尝试插入2,3,4 ......,'if'语句的主体永远不会运行,所以什么都没有插入。

    1. 如果在初始值下方插入一个值,则必须修改列表指针本身。但是,正如@EOF所提到的那样,您试图通过获取其地址来修改传递给函数的值。这不行。 & l没有给你传递的List的地址,它给你在insert()的堆栈上的本地副本的地址。你最好修改“就地”列表的第一个元素的值。如果你真的想让List参数变为可变,你需要将它作为List *传递,并用列表的地址调用函数(例如insert(& n,2);)你的delete()函数遇到同样的问题 - 尝试删除列表的第一个元素。
    2. 尝试使用插入功能:

      void insert(List l, int value)
      {
        List p;
      
        // Find end of list or highest item less than value
        for(p = l; p->next != NULL && p->next->value < value; p = p->next);
      
        if (p->value >= value) {
          // Over-write p with new value, and insert p as a new one after.
          // This saves having to modify l itself.
          int tmpval = p->value;
          p->value = value;
          p->next = new_node(tmpval, p->next);
        } else {
          // Insert new item after p
          p->next = new_node(value, p->next);
        }
      }
      

      评论:您使用指针的方式可能无助于调试过程。

      例如,您的print_list()可以像这样重写:

      void print_list(List l){
        List aux;
        for(aux = l; aux != NULL; aux = aux->next)
          printf("Valor: %d\n", aux->value);
      }
      

      并且仍然表现相同。通常,不要通过在typedef中包含'*'来“隐藏”指针的类似指针的性质。 例如,如果您按以下方式定义列表:

      typedef struct node{
        int value;
        struct node *next;
      } List
      

      并将其传递给这样的函数:

      my_func(List *l, ...)
      
      然后它会使这些问题更加明显。希望这会有所帮助。

答案 1 :(得分:1)

您的代码中存在许多问题:

  • 隐藏typedef背后的指针是一个坏主意,它会给程序员和读者带来困惑。

  • 您必须确定初始节点是否为虚拟节点,或者空列表是否只是NULL指针。后者更易于处理,但您必须将头节点的地址传递给insertdelete,以便他们可以更改头节点。

  • printlist不需要间接指针,尤其是从作为参数传递的指针的地址开始。通过直接使用Node指针简化。

  • insert中您正确地在下一个更高节点之前插入新节点,但您应该从该函数返回。相反,您将跳出开关并执行附加代码,将具有相同值的新节点替换为插入节点,并使用NULL下一个指针。这是5插入4时被移除和丢失的原因。此外,您应该传递头节点的地址,以便可以在第一个节点之前插入节点。

  • delete从参数的地址开始。它无法删除头节点,因为调用者空间中的指针不会更新。您应该传递头节点的地址。

  • 你应该避免在C代码中使用newdelete之类的C ++关键字:虽然不是非法的,但它会使用于C ++的读者感到困惑,混淆语法高亮显示并阻止C ++编译器的编译

以下是简化版本:

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

typedef struct Node {
    int value;
    struct Node *next;
} Node;

Node *new_node(int value, Node *next_node) {
    Node *node = malloc(sizeof(*node));
    if (node != NULL) {
        node->value = value;
        node->next = next_node;
    }
    return node;
}

void print_list(Node *list) {
    for (; list != NULL; list = list->next)
        printf("Valor: %d\n", list->value);
}

void insert_node(Node **p, int value) {
    while ((*p) != NULL && (*p)->value < value)
        p = &(*p)->next;

    *p = new_node(value, *p);
}

void delete_node(Node **p, int value) {
    while (*p != NULL) {
        if ((*p)->value == value) {
            Node *found = *p;
            *p = (*p)->next;
            free(found);
            // return unless delete() is supposed to remove all occurrences
            return;
        } else {
            p = &(*p)->next;
        }
    }
}

int main(void) {
    Node *n = NULL;
    insert_node(&n, 2);
    insert_node(&n, 3);
    insert_node(&n, 5);
    insert_node(&n, 4);
    insert_node(&n, 1);
    print_list(n);
    delete_node(&n, 3);
    print_list(n);
    delete_node(&n, 1);
    print_list(n);
    return 0;
}