简体   繁体   English

检查指针是否为NULL会产生分段错误

[英]Checking if pointer is NULL gives segmentation fault

The problem statement: We have to delete every alternate node of a Linked List. 问题陈述:我们必须删除链接列表的每个备用节点。 Eg: Original list: 1->2->3->4->5 to: 1->3->5 例如:原始清单:1-> 2-> 3-> 4-> 5到:1-> 3-> 5

complete problem statement: https://practice.geeksforgeeks.org/problems/delete-alternate-nodes/1/?ref=self 完整的问题陈述: https : //practice.geeksforgeeks.org/problems/delete-alternate-nodes/1/?ref=self

As you can see, this is a function problem so I'm not actually writing the complete code(just have to complete the function). 如您所见,这是一个函数问题,因此我实际上并没有编写完整的代码(只需要完成函数即可)。 Here is the code that I'm writing: 这是我正在编写的代码:

void deleteAlt(struct Node *head){
    // Code here
    struct Node *traverse=head,*alternate=head->next;

    if(alternate->next==NULL)
    {
        head->next=NULL;
        return;
    }

    while(traverse->next!=NULL && alternate->next!=NULL)
    {
        traverse->next = alternate->next;
        traverse = traverse->next;
        alternate = traverse->next;
        if((alternate->next)==NULL) //presence of this if statement causes segmentation fault
        {
            traverse->next=NULL;
        }
    }
}

I have gone through similar problems on stackoverflow but their code and objective were different, like, not initializing the pointer and comparing it. 我在stackoverflow上遇到了类似的问题,但是它们的代码和目标是不同的,例如,不初始化指针并进行比较。 However, my problem is different. 但是,我的问题不同。

In the case when number of nodes is even, alternate is always going to be NULL and hence there should be no initialization problem. 在节点数为偶数的情况下, alternate始终为NULL,因此应该没有初始化问题。

you do 你做

while(traverse->next!=NULL && alternate->next!=NULL)
  traverse->next = alternate->next;
  traverse = traverse->next;
  alternate = traverse->next;
  if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact 所以事实上

while(traverse->next!=NULL && alternate->next!=NULL)
  traverse = alternate->next;
  alternate = traverse->next;
  if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact 所以事实上

while(traverse->next!=NULL && alternate->next!=NULL)
  alternate = alternate->next->next;
  if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact 所以事实上

while(traverse->next!=NULL && alternate->next!=NULL)
  if((alternate->next->next->next)==NULL) //presence of this if statement causes segmentation fault

when alternate->next->next is NULL (not checked by the while ) alternate->next->next->next causes your segmentation fault alternate->next->next为NULL(不被while检查)时, alternate->next->next->next导致分段错误


A solution is : 一个解决方案是:

void deleteAlt(struct Node * head)
{
  if (head != NULL) {
    while (head->next != NULL) {
      Node * d = head->next;

      head->next = head->next->next;
      free(d);
      head = head->next;
    }
  }
}

A complete program to prove : 一个完整的程序来证明:

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

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

Node * make(int v, Node * n)
{
  Node * r = malloc(sizeof(Node));

  r->v = v;
  r->next = n;

  return r;
}

void pr(Node * l)
{
  while (l != NULL) {
    printf("%d ", l->v);
    l = l->next;
  }
  putchar('\n');
}

void deleteAlt(struct Node * head)
{
  if (head != NULL) {
    while (head->next != NULL) {
      Node * d = head->next;

      head->next = head->next->next;
      free(d);
      head = head->next;
    }
  }
}

int main()
{
  Node * l = make(1, make(2, make(3, make(4, make(5, NULL)))));

  pr(l);
  deleteAlt(l);
  pr(l);

  /* free rest of list */
  while (l != NULL) {
    Node * n = l->next;

    free(l);
    l = n;
  }
}

Compilation and execution: 编译与执行:

pi@raspberrypi:/tmp $ gcc -pedantc -Wextra l.c
pi@raspberrypi:/tmp $ ./a.out
1 2 3 4 5 
1 3 5 
pi@raspberrypi:/tmp $ 

Execution under valgrind to check memory accesses/leaks valgrind下执行以检查内存访问/泄漏

pi@raspberrypi:/tmp $ valgrind ./a.out
==2479== Memcheck, a memory error detector
==2479== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2479== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2479== Command: ./a.out
==2479== 
1 2 3 4 5 
1 3 5 
==2479== 
==2479== HEAP SUMMARY:
==2479==     in use at exit: 0 bytes in 0 blocks
==2479==   total heap usage: 6 allocs, 6 frees, 1,064 bytes allocated
==2479== 
==2479== All heap blocks were freed -- no leaks are possible
==2479== 
==2479== For counts of detected and suppressed errors, rerun with: -v
==2479== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

(edit) In case the length of the list can be even the definition must be changed to : (编辑)如果列表的长度可以等于,则必须将定义更改为:

void deleteAlt(struct Node * head)
{
  while ((head != NULL) && (head->next != NULL)) {
    Node * d = head->next;

    head->next = head->next->next;
    free(d);
    head = head->next;
  }
}

modifying main to check : 修改main以检查:

int main()
{
  {
    Node * l = make(1, make(2, make(3, make(4, make(5, NULL)))));

    pr(l);
    deleteAlt(l);
    pr(l);

    /* free rest of list */
    while (l != NULL) {
      Node * n = l->next;

      free(l);
      l = n;
    }
  }
  {
    Node * l = make(1, make(2, make(3, make(4, NULL))));

    pr(l);
    deleteAlt(l);
    pr(l);

    /* free rest of list */
    while (l != NULL) {
      Node * n = l->next;

      free(l);
      l = n;
    }
  }
}

Compilation and execution : 编译执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra l.c
pi@raspberrypi:/tmp $ ./a.out
1 2 3 4 5 
1 3 5 
1 2 3 4 
1 3 

and under valgrind : 和在valgrind下:

pi@raspberrypi:/tmp $ valgrind ./a.out
==3450== Memcheck, a memory error detector
==3450== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3450== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3450== Command: ./a.out
==3450== 
1 2 3 4 5 
1 3 5 
1 2 3 4 
1 3 
==3450== 
==3450== HEAP SUMMARY:
==3450==     in use at exit: 0 bytes in 0 blocks
==3450==   total heap usage: 10 allocs, 10 frees, 1,096 bytes allocated
==3450== 
==3450== All heap blocks were freed -- no leaks are possible
==3450== 
==3450== For counts of detected and suppressed errors, rerun with: -v
==3450== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

try this: 尝试这个:

void deleteAlt(struct Node *head){

    struct Node * head_tmp=head;
    struct Node * tmp=NULL;

    while(head_tmp->next!=NULL){

        tmp=head_tmp->next;

        head_tmp->next=tmp->next;

        head_tmp=tmp->next;

        //do something for freeing tmp node 

    }


}

I can see a code smell in 我可以看到一个代码气味

if(alternate->next==NULL)
    {
        head->next=NULL;
        return;
    }

What if i have a single node? 如果我只有一个节点怎么办? In that case alternate points to null. 在这种情况下, alternate指向null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM