2012-04-11 103 views
0

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

#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; 
} 
+3

请重新格式化您的代码以使其更易于阅读。 – 2012-04-11 22:11:29

+4

'insert_croissant()'听起来很好吃! – FatalError 2012-04-11 22:12:01

+3

不要在malloc中返回malloc的返回值。没有理由这样做,它实际上可以隐藏你忘记包含''的事实(没有强制转换,不存在非强制函数返回'int' ,这将失败,但演员隐藏它)。 C没有问题强制将'void *'隐式地指向任何其他指针类型。 – 2012-04-11 22:13:59

回答

0

该代码有一个问题,在某些情况下列表可能会损坏;很容易让列表进入没有正确终止的状态(并且可能会从列表中“失去”节点)。根据其他代码如何操作列表,这种情况可能会导致问题。

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

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

q->suivant = p; 

被执行,列表将是循环和'额外'节点将丢失。

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

+0

谢谢,我现在的代码功能齐全:) – orangepixel 2012-04-12 00:46:48

1
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->val(或p->suivant)会导致段错误。

最常见的方式(在我有限的经验)陷入这种情况是忘记第一指针初始化为0

2

绝不做我相信,这将修复它,但至少有一个错误代码。

考虑其中L被初始化的情况下,但Ñ< L-> 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. 
+0

你说得对。 insert_tete()将设置p-> suivant = p。此外,指向p的指针将不会更新,因此q子链将从p链断开。 – wildplasser 2012-04-11 23:11:36

+0

对不起,额外的答案虽然 - 我一直没有足够的积极性,实际上有特权评论... – Michael 2012-04-11 23:17:50

+0

不,它是优秀的。学习十分钟后我无法发现它。问题是:有太多的别名在四处流动。 (我不能投票,因为我没有注册)**请投票赞成!** – wildplasser 2012-04-11 23:23:32

0

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

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; 

} 
+0

这是好得多,我认为在这种情况下,它是不是一个好主意,使用现有的功能插在头上,谢谢! – orangepixel 2012-04-12 00:44:17