编辑:部分解决。我按照第一个答案的建议将NULL检查切换为while循环检查中的第一个,但是我仍然无法访问除第一个之外的任何队列元素。我可以访问data-> head,但我无法访问data-> head-> next,除非我专门创建一个指向data-> head-> next的节点结构。如果我特意创建该节点(让我们称之为temp),那么temp-> next也是不可访问的。基本上,当我将队列传递给此函数时,>下一个功能完全丢失,我不明白为什么。
我正在为Uni开展一个学校项目,我们在其中构建一个修改后的mergesort(编辑:一位评论者注意到这是TimSort的一种形式),而不是普通的mergesort算法,它将数据集划分为已经排序的块数据,然后重新组合它们理论上减少运行时间 作为集合
的示例3 4 5 2 9 4 3 2
将分成
[3 4 5] [2 9] [4 3 2]
然后按排序顺序合并在一起。我们的特定实现必须使用链表,队列和堆栈来完成 这是我的链表定义和队列定义:
typedef struct node_t
{
int value;
struct node_t * next;
} node_t;
typedef struct queue_t
{
node_t *head, *tail;
} queue_t;
我遇到问题的代码是在标识“运行”的函数中,或者是已经对数据进行排序的数据区域。它将队列作为输入,迭代并识别第一个节点是否小于或大于下一个节点。然后它选择运行哪个循环并将每个值出列到一个新队列中,然后将其作为“运行”返回,该运行是已排序数据的子集。
出于某种原因,每当我尝试使用data-> head-> next或data-> head-> next->值时,它会引发分段错误,即使我知道该节点存在且值存在。我一直在通过gdb运行我的程序来找到错误点,我在Windows上,我不能使用valgrind。
这是我遇到问题的函数的代码:
queue_t * extract_next_run(queue_t * data)
{
queue_t * queue = queue_create();
int ascend = 0;
//when there is only one value in the list
if(data->head->next = NULL)
{
queue_enqueue(queue, queue_dequeue(data));
return queue;
}
//ascending run *CRASHES ON THIS WHILE LOOP*
while(data->head->value <= data->head->next->value && data->head->next != NULL)
{
queue_enqueue(queue, queue_dequeue(data));
//not sure if this improves runtime over just "ascend = 1" every iteration
if(ascend != 1)
ascend = 1;
}
//descending run
while(data->head->value > data->head->next->value && data->head->next != NULL)
{
queue_enqueue(queue, queue_dequeue(data));
}
if(ascend == 0)
queue_reverse(queue);
queue->tail->next = NULL;
return queue;
}
这就是让我难以理解的原因:
//things I have tested in this function
printf("%d", data->head->value); // works fine
printf("%d", data->head->next->value); // segmentation fault
data->head = data->head->next; //segmentation fault
if(data->head->next == NULL) //works fine
node_t * temp = data->head->next; // works fine
printf("%d", temp->value); // works fine
temp = temp->next; //segmentation fault
另一件令我烦恼的事情是我能够在其他函数中使用queue-&gt; head = queue-&gt; head-&gt; next并且它工作正常,我可以使用node = node-&gt; next它工作正常,所以我真的不知道问题是什么。我知道这个函数调用的函数有效,但我很乐意为它们提供代码。这里有声明,如果需要我可以提供我的所有代码(不想让这个问题太长):
// mallocs a queue and sets its head and tail to NULL
queue_t * queue_create();
// takes a value and adds it to the end of the queue
void queue_enqueue(queue_t * queue, int data);
// removes the first node of the queue and returns its value
int queue_dequeue(queue_t * queue);
// takes a queue, reads it into a stack,
// then uses stack_pop to return values in reverse order
void queue_reverse(queue_t * queue);
我将非常感谢任何帮助,我一直在努力弄清楚问题是什么,但到目前为止我没有成功。提前谢谢!
答案 0 :(得分:3)
你已经将问题缩小到这个循环:
while(data->head->value <= data->head->next->value && data->head->next != NULL) {
实际上,您似乎正在指责循环控制表达式。那么考虑一下这个表达式:为什么它包含data->head->next != NULL
的测试?
考虑当条件的这一部分为假时 - 即data->head->next == NULL
为真时会发生什么。在首次评估&&
的左侧操作数(包括评估data->head->next->value
)之前,程序不会(永远)评估该条件,并且当data->head->next
为空时会产生未定义的行为。您可能根本没有进行空检查,实际上,某些编译器可能会对其进行优化。
要使空检查有效,必须在 之前对其进行评估,以保护其中的任何评估。
答案 1 :(得分:0)
我修复了它,我的函数中的第一个if语句是if(queue->head->next = NULL)
,但我应该if(queue->head->next == NULL)
。我使用了赋值运算符=
而不是比较运算符==
,它将queue->head->next
分配给NULL
,这导致了段错误。