在C语言中使用链表

在C语言中使用链表,c,pointers,linked-list,C,Pointers,Linked List,我正在学习C语言编程,我遇到了一些麻烦,尤其是在使用指针时。这对我来说有点困难,因为我们在Java或C中不使用指针 我试图做的是创建一个链表(在互联网上找到的代码)并在其中推送元素。就像下面的代码一样 当我取消注释第二行代码时,代码会工作,但我会收到以下列表作为答案{0,1,2},即使我没有在列表中输入数字0。我想得到这个答案:{1,2} int main (){ node_t * test_list = NULL; //test_list = malloc(sizeof(no

我正在学习C语言编程,我遇到了一些麻烦,尤其是在使用指针时。这对我来说有点困难,因为我们在Java或C中不使用指针

我试图做的是创建一个链表(在互联网上找到的代码)并在其中推送元素。就像下面的代码一样

当我取消注释第二行代码时,代码会工作,但我会收到以下列表作为答案{0,1,2},即使我没有在列表中输入数字0。我想得到这个答案:{1,2}

int main (){
    node_t * test_list = NULL;

    //test_list = malloc(sizeof(node_t));

    push(test_list, 1);
    push(test_list, 2);

    print_list(test_list);

    return 0;
}
这是代码的样子:

typedef struct node
{
  int val;
  struct node * next;
}              node_t;

void print_list(node_t * head)
{
  node_t * current = head;

  while (current != NULL)
    {
      printf("%d\n", current->val);
      current = current->next;
    }
}

node_t* new_node(node_t * head)
{
  node_t * head2 = malloc(sizeof(node_t));

  return  head2;
}

void push(node_t * head, int val)
{
  if (head == NULL)
    {
      head = new_node(head);
      head->val = val;
      head->next = NULL;
    }
  else
    {
      node_t * current = head;
      while (current->next != NULL)
          current = current->next;

      /* now we can add a new variable */
      current->next = malloc(sizeof(node_t));
      current->next->val = val;
      current->next->next = NULL;
    }
}
在push函数中,我决定检查head是否等于NULL。如果是这样,我只想创建一个新节点并将其分配给它。我不知道这是不是个好办法。然而,它不起作用

如果有人能指引我走上正确的道路,我将不胜感激

谢谢大家!

(代码来源:)



尝试以下功能

node_t * new_node( int val )
{
    node_t * n = malloc( sizeof( node_t ) );

    if ( n )
    {
        n->val = val;
        n->next = NULL;
    }

    return  n;
}

void push( node_t **head, int val ) 
{
    node_t *n = new_node( val );

    if ( n )
    {
        while ( *head ) head = &( *head )->next;
        *head = n;
    }
}
函数push必须像

push( &test_list, 1 );

至于您的函数
push
实现,那么它将处理
测试列表的副本。因此,
test\u list
的原始值没有改变。

我将尝试解释额外元素0

test_list = malloc(sizeof(node_t)); //this changes the pointer test_list                
                                    //which is initially NULL to a non-NULL pointer, hence the mysterious extra element "0"

 push(test_list, 1);

void push(node_t * head, int val) {
if (head == NULL) //head is not NULL at this point because you called malloc earlier on it, so 1 will be inserted in the next position
{...}
您应该在malloc之后使用一些值初始化列表的头:

test_list = malloc(sizeof(node_t));


head->val = 5; //some value
head->next = NULL;

push(test_list, 1);
...

现在,第一个元素不是0,而是5。

莫斯科的Vlad和Violeta Marin已经发布了它不起作用的原因。我对你的代码做了一些更改,使它起作用

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

  typedef struct node
  {
     int val;
     struct node * next;
  } node_t;

  void print_list(node_t * head) 
  {
      node_t * current = head;
      printf("called\n");
      while (current != NULL) {
         printf("%d\n", current->val);
         current = current->next;
      }
  }


  node_t* new_node()
  {
     //you have to return NULL , if malloc fails to allocate memory 
     node_t * head2 = malloc(sizeof(node_t));
     return  head2;
  }

  void push(node_t **head, int val)
  {
      if (*head == NULL)
      {
          printf("null\n");  
         //you have to check the return value of new_node
         (*head) = new_node();
         (*head)->val = val;
         (*head)->next = NULL;
      }
      else {
          printf("not null\n");
          node_t * current = *head;

          while (current->next != NULL) {
              current = current->next;
          }
          /* now we can add a new variable */
          //you have to check the return value of malloc
          current->next = malloc(sizeof(node_t));
          current->next->val = val;
          current->next->next = NULL;
       }
  }

  void my_free(node_t *head)
  {
    node_t *temp= NULL;
    while(head) 
    {
       temp=head->next;
       free(head);
       head=temp;
    }
}
int main ()
{
   node_t *test_list = NULL;
   push(&test_list, 1);
   push(&test_list, 2);
   print_list(test_list);
   my_free(test_list);
   return 0;
}
#包括
#包括
类型定义结构节点
{
int-val;
结构节点*下一步;
}节点t;
无效打印列表(节点头)
{
节点_t*电流=头部;
printf(“称为\n”);
while(当前!=NULL){
printf(“%d\n”,当前->值);
当前=当前->下一步;
}
}
node_t*新节点()
{
//如果malloc无法分配内存,则必须返回NULL
node_t*head2=malloc(sizeof(node_t));
返回头2;
}
无效推送(节点**头部,内部值)
{
如果(*head==NULL)
{
printf(“null\n”);
//您必须检查新_节点的返回值
(*head)=新的_节点();
(*头部)->val=val;
(*head)->next=NULL;
}
否则{
printf(“非空\n”);
节点_t*当前=*头部;
while(当前->下一步!=NULL){
当前=当前->下一步;
}
/*现在我们可以添加一个新变量*/
//您必须检查malloc的返回值
当前->下一步=malloc(sizeof(node_t));
当前->下一步->val=val;
当前->下一步->下一步=空;
}
}
无效我的空闲(节点头)
{
节点温度=NULL;
while(head)
{
温度=头部->下一步;
自由(头);
压头=温度;
}
}
int main()
{
节点测试列表=NULL;
推送(和测试列表,1);
推送(和测试列表,2);
打印测试列表(测试列表);
我的免费(测试列表);
返回0;
}

当您取消注释代码中的下一行时

//test_list = malloc(sizeof(node_t));
在这里,在调用push函数之前分配头指针。 因此,下面的代码行永远不会执行

 if (head == NULL)
    {
        head = new_node(head);
        head->val = val;
        head->next = NULL;}
因为您已经为head指针malloced了一次,并且还没有初始化它,后面跟着两个push函数。因此,您将在列表中看到0/垃圾,1,2而不是1,2

当您为test_列表注释了malloc之后,在下面的代码段中

if (head == NULL)
    {
        head = new_node(head);
        head->val = val;
        head->next = NULL;
    }else
    {

        node_t * current = head;
        while (current->next != NULL) {
            current = current->next;
        }
由于您没有发送test_list的地址(&test_list-您需要使用双指针),因此在
中对head所做的任何更改都不会反映在test_list中

浏览链接以获得清晰的理解- 以下代码:

1) corrects several oversights in the posted code
2) works correctly
3) contains the logic that (generally) is always used to 
   add a node to the end of a linked list
4) demonstrates that to change the contents of a passed in pointer
   the simplest way is to pass '**' 
   and the caller passes the address of the pointer, not the contents of the pointer
5) uses consistent formatting
6) avoids unnecessary/misleading clutter/confusion in the definition of the struct
7) removes unnecessary parameters from functions
8) properly prototypes the functions 
   notice that the new_node() function prototype has '(void)'
   while the actual function body just has '()'

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

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

// prototypes
void          print_list( struct node * head);
struct node * new_node( void );
void          push( struct node ** head, int val);


int main ( void )
{

    struct node * test_list = NULL;

    push(&test_list, 1);
    push(&test_list, 2);

    print_list(test_list);

    return 0;
} // end function: main


// step through linked list, printing the val field from each node
void print_list( struct node * head)
{
    struct node * current = head;

    while (current != NULL)
    {
        printf("%d\n", current->val);
        current = current->next;
    }
} // end function: print_list


// create a new node
struct node * new_node()
{
    struct node * head2 = NULL;

    if( NULL == (head2 = malloc(sizeof( struct node))))
    { // then malloc failed
        // handle error, cleanup, and exit
    }

    return  head2;
} // end function: new_node


// append a new node to end of linked list
// need to use '**' so actual pointer in main() will be updated
void push( struct node ** head, int val)
{
    struct node * current = NULL;

    if (*head == NULL)
    { // then list is empty
        current = new_node();
        current->val = val;
        current->next = NULL;
        *head = current;
    }

    else
    {
        current = *head;

        while (current->next != NULL)
        {
            current = current->next;
        }

        /* now we can append a new node to linked list */
        current->next = new_node();
        current->next->val = val;
        current->next->next = NULL;
    }
} // end function: push
1)纠正了发布代码中的几个疏忽
2) 工作正常
3) 包含(通常)始终用于
将节点添加到链接列表的末尾
4) 演示如何更改传入指针的内容
最简单的方法是通过'**'
调用者传递的是指针的地址,而不是指针的内容
5) 使用一致的格式
6) 避免结构定义中不必要的/误导性的混乱/混乱
7) 从函数中删除不必要的参数
8) 正确地设计函数的原型
请注意,新的_node()函数原型具有'(void)'
而实际的函数体只有'()'
#包括
#包括
结构节点
{
int-val;
结构节点*下一步;
};
//原型
作废打印列表(结构节点*头);
结构节点*新节点(无效);
无效推送(结构节点**head,int val);
内部主(空)
{
结构节点*test_list=NULL;
推送(和测试列表,1);
推送(和测试列表,2);
打印测试列表(测试列表);
返回0;
}//结束函数:main
//逐步浏览链表,打印每个节点的val字段
无效打印列表(结构节点*头)
{
结构节点*当前=头部;
while(当前!=NULL)
{
printf(“%d\n”,当前->值);
当前=当前->下一步;
}
}//结束函数:打印列表
//创建一个新节点
结构节点*新节点()
{
结构节点*head2=NULL;
if(NULL==(head2=malloc(sizeof(struct node)))
{//然后malloc失败了
//处理错误、清理和退出
}
返回头2;
}//结束函数:新建_节点
//将新节点附加到链表的末尾
//需要使用“**”,以便更新main()中的实际指针
无效推送(结构节点**head,int val)
{
结构节点*current=NULL;
如果(*head==NULL)
{//那么列表是空的
当前=新节点();
当前->val=val;
当前->下一步=空;
*水头=电流;
}
其他的
{
电流=*水头;
while(当前->下一步!=NULL)
{
当前=当前->下一步;
}
/*现在我们可以将一个新节点附加到链表中*/
当前->下一步=新建_节点();
当前->下一个->值=v