Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 指向指针的指针-链表混乱_C_Pointers_Linked List - Fatal编程技术网

C 指向指针的指针-链表混乱

C 指向指针的指针-链表混乱,c,pointers,linked-list,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);

我正在编写一个简单的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;
        }
}
此代码(至少)有两个错误:

  • 线路

    如果((*p)->值>值){

  • 这意味着,如果以1作为第一个值开始列表,然后尝试插入2,3,4…,则“if”语句的主体永远不会运行,因此不会插入任何内容

  • 如果在起始值下方插入一个值,则必须修改列表指针本身。但是,正如@EOF所述,您正试图通过获取函数的地址来修改传递给函数的值。这是行不通的。&l没有提供您传递的列表的地址,而是在insert()上提供本地副本的地址“的堆栈。最好修改列表中第一个元素的“就地”值。如果确实要使列表参数可变,则需要将其作为列表*传递,并使用列表的地址调用函数(例如insert(&n,2);)或delete()函数遇到相同的问题-请尝试删除列表的第一个元素
  • 为插入函数尝试以下操作:

    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);
      }
    }
    
    通常,最好不要通过在typedef中包含“*”来“隐藏”指针类似指针的性质。 例如,如果您这样定义列表:

    void print_list(List l){
      List aux;
      for(aux = l; aux != NULL; aux = aux->next)
        printf("Valor: %d\n", aux->value);
    }
    
    typedef struct node{
      int value;
      struct node *next;
    } List
    
    my_func(List *l, ...)
    
    并将其传递给如下函数:

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

    然后,它会使其中一些问题变得更加明显。希望这能有所帮助。

    您的代码中有许多问题:

    • 在typedef后面隐藏指针是一个坏主意,它会导致程序员和读者的混淆

    • 您必须确定初始节点是虚拟节点,还是空列表只是一个
      NULL
      指针。后者更易于处理,但必须将头节点的地址传递给
      insert
      delete
      ,以便它们可以更改头节点

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

    • insert
      中,您可以在下一个更高的节点之前正确插入新节点,但随后应该从函数返回。相反,您中断开关并执行追加代码,将插入的节点替换为具有相同值和空下一个指针的新节点。这就是
      5
      获取remove的原因插入
      4
      时会丢失和丢失。此外,应传递头节点的地址,以便在第一个节点之前插入节点

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

    • <> L> > P>避免C代码中使用C++代码,如<代码>新< /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;
    }
    
    #包括
    #包括
    类型定义结构节点{
    int值;
    结构节点*下一步;
    }节点;
    节点*新节点(int值,节点*下一个节点){
    Node*Node=malloc(sizeof(*Node));
    如果(节点!=NULL){
    节点->值=值;
    节点->下一个=下一个节点;
    }
    返回节点;
    }
    作废打印列表(节点*列表){
    对于(;list!=NULL;list=list->next)
    printf(“值:%d\n”,列表->值);
    }
    void insert_节点(节点**p,int值){
    而((*p)!=NULL&(*p)->value下一步;
    *p=新节点(值,*p);
    }
    void delete_节点(节点**p,int值){
    while(*p!=NULL){
    如果((*p)->value==value){
    Node*found=*p;
    *p=(*p)->下一步;
    自由(找到);
    //除非delete()应该删除所有出现的内容,否则返回
    返回;
    }否则{
    p=&(*p)->下一步;
    }
    }
    }
    内部主(空){
    Node*n=NULL;
    插入_节点(&n,2);
    插入_节点(&n,3);
    插入_节点(&n,5);
    插入_节点(&n,4);
    插入_节点(&n,1);
    打印列表(n);
    删除_节点(&n,3);
    打印列表(n);
    删除_节点(&n,1);
    打印列表(n);
    返回0;
    }
    
    孩子们,这就是为什么你不使用
    typedef
    指针来隐藏指针的原因。你是否尝试过使用调试器?注意,你的列表界面不能捕获所有用例。我建议重写你的程序,使其支持空列表用例。它应该创建一个空列表,而不是一个单元素列表,并且应该能够要处理插入到空列表中的操作,请将元素作为列表的第一个元素插入,并删除列表的第一个/唯一元素。
    insert
    delete
    的签名必须更改才能完成此操作。在
    insert
    函数中,您可以将新元素与下一个元素正确链接,但是忘记在链中插入新元素。实际上我认为
    *p=new;
    应该是类似
    (*p)的东西->next=new;
    @EOF
    typedef
    ing指针没有什么特别的错误。此代码中存在的错误与此无关。假设您从
    typedef
    中删除星号,并将
    List
    替换为
    List*
    无处不在。现在呢?有什么实现了吗?对于您的删除问题,yo不将下一个元素与上一个元素链接:将其与当前元素重新链接。因此,当删除当前元素时,您只会丢失列表的结尾。如果在
    插入()
    中(p->value>=value),为什么要对
    进行特殊处理