【问题标题】:segmentation fault, lists in C分段错误,C 中的列表
【发布时间】:2012-04-11 22:09:11
【问题描述】:

我尝试使用两个函数直接对我在链表中​​输入的数字进行排序,第一个在头部添加元素,第二个包含分段错误应该利用第一个来完成这项工作。

#include <stdio.h>
#include <stdlib.h>
typedef struct cellule
{
    int val;
    struct cellule *suivant;
} cellule;
typedef struct cellule* liste;

liste insert_tete(liste L,int n)
{

    liste p;

    p=malloc(sizeof(cellule));
    p->val=n;
    p->suivant=L;
    return p;
}//ok :)
liste insert_croissant(liste L,int n)
{
    if(!L)
    {
        L=insert_tete(L,n);
        return L;
    }

    liste p,q;
    for(q=L,p=L; (p!=NULL )&&(n> (p->val)) ; q=p,p=p->suivant); //

    p=insert_tete(p,n);
    q->suivant=p;
    return L;
}

【问题讨论】:

  • 请重新格式化您的代码以使其更易于阅读。
  • insert_croissant() 听起来很好吃!
  • 不要在 C 中强制转换 malloc 的返回值。没有理由这样做,它实际上可以隐藏您忘记包含 &lt;stdlib.h&gt; 的事实(没有强制转换,不存在的函数暗示返回int,这将失败,但演员隐藏它)。 C 可以将 void* 隐式强制转换为任何其他指针类型。
  • 另外,描述性变量名也不错。
  • @BrettHale,是的,它定义明确。这里的逗号是一个“逗号运算符”,每个这样的逗号运算符都定义了一个序列点。

标签: c sorting linked-list segmentation-fault


【解决方案1】:

我不相信这会解决它,但您的代码中至少存在一个错误。

考虑初始化L的情况,但是n val:

// p = L, q = L;
// Let L = [val|->...
p=insert_tete(p,n);
// p = [n|->[val|->...
q->suivant=p;
// q = L
// Therefore [val|->[n|->L
// And you've just made your linked list circular.

【讨论】:

  • 你是对的。 insert_tete() 将设置 p->suivant = p。此外,指向 p 的指针不会被更新,因此 q 子链将与 p 链断开连接。
  • 对不起,额外的答案 - 我还不够活跃,实际上没有评论的特权......
  • 不,非常好。研究了十分钟后,我无法发现它。问题是:有太多的别名浮动。 (我不能投票,因为我没有注册)请给家长投票!
  • @wildplasser “未注册”是什么意思?你是这里的常客,不是吗?无论如何,迈克尔,是的,wildplasser 是对的,这是一个很好的答案,它增加了一些新的东西,所以它让你至少 10 点接近评论特权(换句话说,我 +1)。顺便说一句,我也忽略了这一点。
  • 好吧:点击我的简历。它说未注册。是我对 Graucho Marx 的爱使我无法注册。
【解决方案2】:
liste insert_croissant(liste L,int n)
{
    if(!L)
    {
        L=insert_tete(L,n);
        return L;
    }

这里我们知道L 不是NULL

    liste p,q;
    for(q=L,p=L; (p!=NULL )&&(n> (p->val)) ; q=p,p=p->suivant); //

这里获得合法段错误的唯一方法是,p 后面的指针之一是一个非 0 指针,它不指向正确分配的 struct cellule,而是指向一些不可访问的内存。然后尝试访问p-&gt;val(或p-&gt;suivant)会导致段错误。

进入这种情况的最常见方法(以我有限的经验)是忘记将第一个指针初始化为 0。

【讨论】:

    【解决方案3】:

    代码存在列表在某些情况下可能会损坏的问题;很容易使列表进入未正确终止的状态(并且可能从列表中“丢失”节点)。这种情况可能会导致问题,具体取决于其他代码如何操作列表。

    如果您尝试在非空列表中添加新节点,但新值小于或等于第一个节点的值,则列表最终将成为一个包含两个节点的循环列表。位于列表头部的节点之后的所有节点都将丢失。

    发生这种情况是因为在这种情况下pq 在调用insert_tete(p,n) 时都将指向该节点。在insert_tete(p,n) 返回后,p-suivantq 将指向列表头部的节点。所以当

    q->suivant = p;
    

    执行后,列表将是循环的,“额外”节点将丢失。

    根据您的其他操作在列表中的作用方式(尤其是如果/如何删除元素),您可能会发现自己在 suivant 字段中留下了一个悬空指针(这可能会导致段错误),或者最终出现在一个无限循环。

    【讨论】:

      【解决方案4】:

      使用指针对指针的简化版本。注意:空列表没有特殊情况。

      struct cellule {
          int val;
          struct cellule *suivant;
          };
      
      struct cellule *insert_croissant(struct cellule **LL, int val)
      {
      
          struct cellule *p,**pp;
      
          for(pp=LL  ; *pp && (*pp)->val < val ; pp = &(*pp)->suivant) {;}
            /* When we arrive here, pp points to whatever pointer happens
            ** to point to our current node.
            ** - If the list was empty, *pp==NULL
            ** - if the place to insert happens to be the tail of the list, *p is also NULL        
            ** - in all cases, *pp should be placed after the new node, and the new node's pointer should be assigned to *pp
            */
          p = malloc(sizeof *p);
          p->val = val;
          p->suivant = *pp;
          *pp = p;
      
          return *LL;
      
      }
      

      【讨论】:

      • 这个好多了,我认为在这种情况下使用在头部插入的现有函数不是一个好主意,谢谢!
      猜你喜欢
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 2012-06-12
      • 2020-09-10
      相关资源
      最近更新 更多