【问题标题】:Sorting a linked-list (mystery segfault)对链表进行排序(神秘的段错误)
【发布时间】:2012-02-10 14:58:24
【问题描述】:

我目前正在将 C 中的链表排序为家庭作业。我不是在寻找代码 sn-p 作为答案,因为我了解自己弄清楚它的价值。我使用下面的函数收到一个段错误,如果有人至少能告诉我原因,我将不胜感激。我能想到的最好的结果是到达以下行时它失败了:

if ( head->value > head->next->value ) {

编辑:将此行更改为 if (head->next != NULL && head->value > head->next->value){ 并且不再接收段错误。但是,我的输出头指针给了我链表中的最后一个节点。暂停。

我不完全确定从这里往哪里走,即使是在正确方向上的最轻微的推动也会非常感激。

struct node *sort_list(struct node *head) {
    bool swapped ;
    struct node * tmp , * orig ;
    orig = head ;

    if ( head == NULL || head->next == NULL ) return head ;
    else {
            do {
                    swapped = false ;
                    if ( head->next != NULL && head->value > head->next->value ) {
                            tmp = head ;
                            head = head->next ;
                            tmp->next = head->next ;
                            head->next = tmp ;

                            swapped = true ;
                    }
                    head = head->next ;
            } while ( swapped == true && head != NULL ) ;
    }
    return orig ;
}

【问题讨论】:

  • 我没有立即看到问题,但如果我是你,我会创建一个 swap(...) 函数,该函数接受交换代码并将其放入自己的函数中。然后您可以测试该功能,直到您确信它可以工作。一旦你有了它,你就可以专注于你的排序逻辑。就目前而言,您必须首先弄清楚是您的排序逻辑还是交换逻辑搞砸了。
  • 花时间学习如何使用调试器是值得的。这样就不需要问这样的问题(以及许多其他问题),而且你会更快地完成更多工作。
  • 不是学习调试器的问题,只是我需要更好地使用它。我的路还很长!
  • 虽然我认为您目前得到的答案很有用而且可能是正确的,但将来最好通过包含导致代码失败的 测试用例 来处理这些问题。单项列表,不需要交换的双项列表,确实需要交换的双项列表,一些完全颠倒的三项列表,大多已排序,并且已经排序等。这些案例中的一小部分可以改变世界。

标签: c sorting pointers linked-list


【解决方案1】:

当您进入do 循环时,您知道head->next 不是NULL,但是下一轮,或者当您到达最后一项时呢?最后一项之后没有任何内容。

编辑:

假设您依次有 3 个项目,ABC,其中 head == B,并且您想要交换项目 BC。你没有考虑到你还需要做A->next = C

【讨论】:

  • 编辑原件。我仍然收到不正确的输出;见 OP。
【解决方案2】:

这很可能是由 NULL 指针取消引用引起的。

您没有在循环中检查 head->next 是否为 NULL。在第一次迭代之后,head 变为 head->next,并且您的条件 (if (head->value > head->next->value)) 正在取消引用 head 以访问 valuenext->value

【讨论】:

  • 编辑原件。我仍然收到不正确的输出;见 OP。
【解决方案3】:

head->next 可能为空。您正在检查它是否在循环之前,但 while 条件不会执行该检查。

你应该找到一个gdb 教程,它是一个非常强大的工具,可以处理这样的事情。

【讨论】:

  • 编辑原件。我仍然收到不正确的输出;见 OP。
  • gdb 很棒,但他可能还需要一个学期的时间
  • 其实上周我的第一次gdb讲座。不过还是很新。
  • 太好了。在第一次看到段错误后,我直到 2 或 3 年才使用 gdb。我不得不依靠打印报表并在纸上跟踪我的程序。 ......很多不眠之夜。
【解决方案4】:

一旦 head 成为链表中的最后一个元素,就会出现段错误。
我不想编写代码,因为它是家庭作业,但添加一个条件来检查 head->next 是否为空。如果是,您需要将 head 设置回列表的开头。

您的冒泡排序需要多次遍历链表才能对其进行排序。如果您使用值 5、4、3、2、1 初始化链接列表并打印头并打印温度和头。你可能会看到 5,4 5,3 5,2 5,1 段错误

而且你的排序公式似乎有点不对劲。如果你有 2,3,1 之类的数据。您的代码会看到 2 和 3,交换后将变为 true,并且函数将返回 true。

您可能希望在内部使用循环进行循环,以便外部循环的每次迭代都会导致 1 次通过链表。如果在遍历整个链表后没有交换,则对数据进行排序。

do{
    for 1 pass through linked list (this can be a for or while loop)
        swap if necessary; set swapped to true
}while(swapped is true)

希望这会有所帮助。

编辑

之后

tmp = head;

添加

head = head->next  
if(tmp == orig)  
    orig = head;  

您需要维护您的头指针。
在 5、4、3、6 的情况下。它将按如下方式排序
4,5,3,6
4,3,5,6
3,4,5,6
但是您的 orig 指针从未更新,因此您的输出将被截断为 4,5,6。

【讨论】:

  • lmk 如果这修复了排序错误。看来您已经修复了 seg 错误。
  • 我已经将我的算法重写为这个,但我仍然得到不正确的输出。排序后如何处理挂在指向第一个节点的指针?
  • 检查编辑,你需要在你的代码中维护你的 orig 指针。
猜你喜欢
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多