C 插入到链表中总是返回最后一个节点,而不是当前节点

C 插入到链表中总是返回最后一个节点,而不是当前节点,c,C,所以我在写一个程序,创建一个dinamic列表,在最后一个节点后插入一个新节点,最后打印新创建的列表。我希望当我打印它时,它实际上会连续打印当前节点的编号,比如Info:1,Info:2,Info:3,但它总是打印最后一个节点。我猜这是指针错误,但不能真正找到什么 #include <stdio.h> #include <stdlib.h> struct node{ int info; struct node* pNext; }; typedef struct

所以我在写一个程序,创建一个dinamic列表,在最后一个节点后插入一个新节点,最后打印新创建的列表。我希望当我打印它时,它实际上会连续打印当前节点的编号,比如Info:1,Info:2,Info:3,但它总是打印最后一个节点。我猜这是指针错误,但不能真正找到什么

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

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

typedef struct node Node;

void tail_insertion(Node* pFirst, Node* pLast);
void print_list(Node* pFirst);

static int n=3;

int main()
{
    Node *pFirst=NULL, *pLast=NULL;
    tail_insertion(pFirst, pLast);
}

void tail_insertion(Node* pFirst, Node* pLast){
  // Creation of a new node in the heap
  Node *pNew = (Node*) malloc(sizeof(Node));
  pNew->info=0;
  pNew->pNext= NULL;

  for(int i=0; i<3;i++){
    if(pFirst == NULL){// No node in the list
      pNew->info++;
      pFirst = pNew; // The first node is the newly created one
      pLast = pNew; // The last node is the newly created one
      printf("Ok the list was empty\n");
    }
    else{
      // Else, there is already at least one node in the list
      pNew->info++;
      pLast-> pNext= pNew; // the last node becomes the second one
      pLast= pNew; // The last node is the newly created one
      printf("Ok the list wasn't empty\n");
    }
  }
  print_list(pFirst);
  return;
}


void print_list(Node* pFirst){
  if(pFirst == NULL){
    printf("No node in the list!\n");
  }
  else{
    // New pointer used to scan the list.
    Node* pScan = pFirst;
    do{
      printf("Info: %d\n", pScan->info);
      // ptrScan is updated to point to the next node in the
      // list
      pScan = pScan->pNext;
    }while(pScan!= NULL && --n); //NULL when this was the last node
  }
  return;
}
两个问题:

您没有将指针传递到列表指针节点*->节点** 您试图将同一节点插入三次,并将malloc移动到循环中 我猜静态int n=3,而-n可能是为了修复print_列表中的无休止循环而添加的,因为pscan->pNext在原始代码中生成了pscan

修复和清理代码:

包括 包括 typedef结构节点; 类型定义结构节点{ 国际信息; 节点*pNext; }节点; 静态无效打印\u列表节点*pFirst{ //用于扫描列表的新指针。 节点*pScan=pFirst; 而pScan{ printfInfo:%d\n,pScan->info; //ptrScan更新为指向中的下一个节点 //名单 pScan=pScan->pNext; } } 静态无效尾部插入节点**p第一,节点**pLast{ 对于int i=0;iinfo=i+1; pNew->pNext=NULL; 如果*pFirst==NULL{//列表中没有节点 *pFirst=pNew;//第一个节点是新创建的节点 *pLast=pNew;//最后一个节点是新创建的节点 printfOk列表为空\n; }else{//else,列表中至少已有一个节点 *pLast->pNext=pNew;//最后一个节点成为第二个节点 *pLast=pNew;//最后一个节点是新创建的节点 printfOk列表不是空的\n; } } 打印列表*pFirst; } int main argc,char*argv[]{ Node*pFirst=NULL; Node*pLast=NULL; 尾翼插入、首件和塑料件; } 试运行:

$gcc-Wall-Werror-o dummy.c 美元/虚拟 好的,列表是空的 好的,列表不是空的 好的,列表不是空的 信息:1 信息:2 信息:3 两个问题:

您没有将指针传递到列表指针节点*->节点** 您试图将同一节点插入三次,并将malloc移动到循环中 我猜静态int n=3,而-n可能是为了修复print_列表中的无休止循环而添加的,因为pscan->pNext在原始代码中生成了pscan

修复和清理代码:

包括 包括 typedef结构节点; 类型定义结构节点{ 国际信息; 节点*pNext; }节点; 静态无效打印\u列表节点*pFirst{ //用于扫描列表的新指针。 节点*pScan=pFirst; 而pScan{ printfInfo:%d\n,pScan->info; //ptrScan更新为指向中的下一个节点 //名单 pScan=pScan->pNext; } } 静态无效尾部插入节点**p第一,节点**pLast{ 对于int i=0;iinfo=i+1; pNew->pNext=NULL; 如果*pFirst==NULL{//列表中没有节点 *pFirst=pNew;//第一个节点是新创建的节点 *pLast=pNew;//最后一个节点是新创建的节点 printfOk列表为空\n; }else{//else,列表中至少已有一个节点 *pLast->pNext=pNew;//最后一个节点成为第二个节点 *pLast=pNew;//最后一个节点是新创建的节点 printfOk列表不是空的\n; } } 打印列表*pFirst; } int main argc,char*argv[]{ Node*pFirst=NULL; Node*pLast=NULL; 尾翼插入、首件和塑料件; } 试运行:

$gcc-Wall-Werror-o dummy.c 美元/虚拟 好的,列表是空的 好的,列表不是空的 好的,列表不是空的 信息:1 信息:2 信息:3 通用代码分析 我们考虑泰勒插入…你希望它做什么:

创建一个新节点; 你给它正确的价值观; 启动for循环的目的是基于特定条件创建更多节点; 打印整个列表以检查其是否有效; 现在,看看你的尾部插入代码。。。删除功能注释:

请注意,我已删除退货。。。因为它不是必需的。这是不必要的,因为尾部插入。。。类型无效

另外,pNew->info正在存储我读取时的节点ID。因此,将i分配给它应该不是一个问题。如有必要,进行适当的更改

最后说明 有评论说你不需要塑料。虽然这是事实,但您需要考虑:

如果只使用pFirst,则需要确保在pFirst->pNext中插入新节点后,执行pFirst->pNext->pNext=NULL。这样,您就可以通过比较NULL来知道何时到达列表的末尾; 如果您继续使用pLast,您可以与pLast进行比较,以了解该地址是否是列表中的最后一个地址。显然,在我的修复之后,您也可以将其与NULL进行比较; 考虑尾随 从长远来看,使用pLast可以大大简化工作,减少CPU的使用; 你可能知道,但你应该把打印列表放在第一位;在主。。。使事情更有条理的功能。而且,它使我的代码强迫症达到新的绝望水平-

通用代码分析 我们考虑泰勒插入…你希望它做什么:

创建一个新节点; 你给它正确的价值观; 启动for循环的目的是基于特定条件创建更多节点; 打印整个列表以检查其是否有效; 现在,看看你的尾部插入代码。。。删除功能注释:

请注意,我已删除退货。。。因为它不是必需的。这是不必要的,因为尾部插入。。。类型无效

另外,pNew->info正在存储我读取时的节点ID。因此,将i分配给它应该不是一个问题。如有必要,进行适当的更改

最后说明 有评论说你不需要塑料。虽然这是事实,但您需要考虑:

如果只使用pFirst,则需要确保在pFirst->pNext中插入新节点后,执行pFirst->pNext->pNext=NULL。这样,您就可以通过比较NULL来知道何时到达列表的末尾; 如果您继续使用pLast,您可以与pLast进行比较,以了解该地址是否是列表中的最后一个地址。显然,在我的修复之后,您也可以将其与NULL进行比较; 考虑到尾部插入,使用pLast可以大大简化工作,并从长远来看减少CPU的使用;
你可能知道,但你应该把打印列表放在第一位;在主。。。使事情更有条理的功能。而且,它使我的代码强迫症达到新的绝望水平-

提示:pFirst的值不会在函数外部更改。@EugeneSh。那我该怎么办?你为什么需要橡皮膏?似乎是多余的,没有检查错误?@NeilEdelman我用它来指向列表的末尾,这样我就知道在结构节点中插入新节点的位置你有一个节点元素,它指向链接列表中的下一个节点变量,您可以使用它来查找列表的结尾。提示:pFirst的值在函数之外不会更改。@EugeneSh。那我该怎么办?你为什么需要橡皮膏?似乎是多余的,没有检查错误?@NeilEdelman我用它来指向列表的末尾,这样我就知道在结构节点中插入新节点的位置。如果有一个节点元素指向链接列表中的下一个节点变量,你可以用它来查找列表的结尾。是的,我添加了-n来尝试修复循环。谢谢你是的,我加了-n来修复这个循环。谢谢你我考虑的另一个设计决定是头部插入,它允许pFirst成为唯一的真相来源,允许O1插入,基本上是一个堆栈。谢谢你的解释,它非常详尽!我现在发现了这个缺陷。我会考虑的另一个设计决策是头部插入,它允许pFirst成为唯一的真相来源,并允许O1插入,基本上是一个堆栈。谢谢你的解释,它非常详尽!我现在发现了缺陷。
Ok the list was empty
Ok the list wasn't empty
Ok the list wasn't empty
Info: 3
Info: 3
Info: 3
Node *pNew = (Node*) malloc(sizeof(Node));

pNew->info=0;
pNew->pNext= NULL;

for(int i=0; i<3;i++){

    if(pFirst == NULL){

        pNew->info++;

        pFirst = pNew;
        pLast = pNew;

        printf("Ok, the list was empty.\n");

    } else {

        pNew->info++;

        pLast-> pNext= pNew;
        pLast= pNew;

        printf("Ok, the list wasn't empty.\n");

    }

}

print_list(pFirst);
Node *pNew; /* Declaring pNew *without* assignment. */

for(int i = 0; i < 3; i++){

    pNew = (Node*) malloc(sizeof(Node)); /* Allocation of new memory address. */

    pNew->info  = i; /* pNew->info works like an ID in you current code. */

    pNew->pNext = NULL; /* It is proper to assign NULL */

    if(pFirst == NULL){

        pNew->info++;

        pFirst       = pNew;
        pLast        = pNew;

        printf("The list was empty.\n");

    } else {

        pNew->info++;

        pLast->pNext = pNew;
        pLast        = pNew;

        printf("The list wasn't empty.\n");

    }
}

print_list(pFirst);