【问题标题】:How to fix linked-list Segmentation fault C如何修复链表分段错误 C
【发布时间】:2019-06-20 00:27:59
【问题描述】:

我正在尝试在以下代码中解决“分段错误”的问题, 我可能认为我没有得到全貌,这就是为什么我不断获得分段错误而不是分段错误, 任何有助于深入理解这一点的帮助都会鼓励我进行自我分析。

代码应该简单明了:给定两个列表,我想从第一个列表中删除第二个列表中出现的所有元素, 我的努力是:

typedef struct EL {
    int info;
    struct EL *next;
} ElementoLista;

typedef ElementoLista *ListaDiElementi;

void filterLists(ListaDiElementi *lista1,ListaDiElementi *lista2) {

  ListaDiElementi aux = *lista1,aus = *lista2,corr;

  while(aux != NULL) {
    if(aux->info == aus->info) {    // Erase from the first
      corr = aux;
      aux = aux->next;
      free(corr);
    }           
    else {              
      if(aus != NULL)       //Increase the second
        aus = aus->next;
      else {
        aus = *lista2;          //Restart
        aux = aux->next;
      }
    }       
  }
}

【问题讨论】:

  • 不要不在 typedef 中隐藏指针。它会导致问题:typedef ElementoLista* ListaDiElementi;
  • @PaulOgilvie 不要认为那是问题,但是好的,谢谢
  • 如果 aux 不为 null 但 aus 为 null aux->info==aus->info 会导致问题吗?
  • 应该进入else的else,不是吗?两个列表总是至少有一个元素@Spinkoo
  • 这似乎是learn how to debug your programs 的好时机。

标签: c pointers linked-list free


【解决方案1】:

我想这两个列表中元素的顺序无关,一个解决方案可以是:

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

typedef struct EL {
    int info;
    struct EL *next;
} ElementoLista;

ElementoLista * make(int i, ElementoLista * n)
{
  ElementoLista * r = malloc(sizeof(ElementoLista));

  if (r == NULL) {
    /* change that code with what you want */
    puts("out of memory");
    exit(-1);
  }

  r->info = i;
  r->next = n;
  return r;
}

/* I suppose nothing about the order of the element in the two lists */
void filterLists(ElementoLista ** plista1, ElementoLista * lista2) {
  /* have to work on plista1, not on a var valuing *plista1,
     to be able to update it when a cell is removed */
  while (*plista1 != NULL) {
    ElementoLista * p;

    /* is the info present in the second list ? */
    for (p = lista2; p != NULL; p = p->next) {
      if ((*plista1)->info == p->info) {
        /* remove the cell */
        ElementoLista * rmv = *plista1;

        *plista1 = (*plista1)->next;
        free(rmv);
        break;
      }
    }

    if (p == NULL)
      /* the current cell was not removed, go to the next */
      plista1 = &(*plista1)->next;
  }
}

void pr(ElementoLista * l)
{
  putchar('{');
  while (l != NULL) {
    printf(" %d", l->info);
    l = l->next;
  }
  puts(" }");
}

int main()
{
  ElementoLista * l1 = make(1, make(2, make(3, make(4, 0))));
  ElementoLista * l2 = make(3, make(1, 0));

  pr(l1);
  filterLists(&l1, l2);
  pr(l1);

  return 0;
}

我删除了你的 typedef 隐藏指针,这样做是个坏主意,因为这会打扰读者

如你所见,给出第二个列表的指针地址是没有用的,因为那个没有被修改

执行:

{ 1 2 3 4 }
{ 2 4 }

【讨论】:

  • 不要将错误消息打印到stdout。 -1 在大多数系统上不是有效的退出状态。
  • @bruno,其实这两个列表是排序的
  • @jacopoburelli 为什么您的问题中没有这些信息?上面的代码即使有排序也能工作,只要知道有排序就可以优化它。可以很好地锻炼你的进步,我知道这样做^^
  • @jacopoburelli 我在我的解决方案中添加了 cmets
【解决方案2】:

您的代码有几个问题:

  • 当第二个列表比另一个短时,你会得到一个段错误,因为你没有在第一个 if 语句中检查 aus 是否为 NULL。

  • 如果第一个列表中间的元素被删除,你稍后会得到另一个段错误,因为被删除元素的前驱仍然指向原始元素,但释放了内存。

    李>
  • 我不知道这是否是个问题,但您的算法似乎只适用于排序列表,请查看这两个列表,例如 [1,2] 和 [2,1]。

为了帮助您使用算法,我们需要知道您喜欢如何处理重复元素以及列表是否已排序。

【讨论】:

  • 是的应该排序
猜你喜欢
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2015-07-15
  • 1970-01-01
  • 2021-06-03
相关资源
最近更新 更多