所以现在我正在尝试实现一个deltaclock,我正在尝试的第一步是首先创建一个使用双链表的优先级队列(稍后我会做其他的deltaclock内容)。从优先级队列中弹出的第一个元素是位于链表(或deltaClock结构)根目录的元素。
我在我的测试中将几个元素推送到队列中,并且在一些弹出操作之后,有一个案例,当它从几乎空的列表中弹出时会出现段错误。
当我在弹出方法中注释掉行中我说“clock-> root-> previous = 0;”时,当弹出元素时,main方法中的程序不会出现段错误。但是,由于前一个节点不再存在,因此需要删除指向前一个节点的指针。
当我执行弹出操作时,如何才能使新根的前一个指针为空?
#include <stdio.h>
#include <stdlib.h>
struct deltaNode{
int tics; // source
struct deltaNode* next;
struct deltaNode* previous;
};
struct deltaClock{
struct deltaNode* root;
struct deltaNode* tail;
int size;
};
void initDeltaClock(struct deltaClock **clock){
(*clock) = malloc(sizeof(struct deltaClock));
(*clock)->size = 0;
}
void push(struct deltaClock* clock, int numberOfTics){
if(clock->root == 0){
// root is empty, initialize it.
clock->root = malloc(sizeof(struct deltaNode));
clock->root->tics = numberOfTics;
clock->tail = clock->root;
}
else {
struct deltaNode* newNode = malloc(sizeof(struct deltaNode));
newNode->tics = numberOfTics;
struct deltaNode* temp = clock->root;
if(newNode->tics < temp->tics){
clock->root->previous = newNode;
newNode->next = clock->root;
clock->root = newNode;
} else {
while(newNode->tics > temp->tics){
if(temp->next == 0){
break;
}
temp = temp->next;
}
if(temp->next == 0 && newNode->tics > temp->tics){
clock->tail->next = newNode;
newNode->previous = clock->tail;
clock->tail = newNode;
}
else{
temp->previous->next = newNode;
newNode->previous = temp->previous;
newNode->next = temp;
temp->previous = newNode;
}
}
}
clock->size++;
}
int pop(struct deltaClock* clock){
struct deltaNode* temp = clock->root;
if(temp == 0){
return -1;
}
int result = temp->tics;
clock->root = clock->root->next;
clock->root->previous = 0;
free(temp);
clock->size--;
return result;
}
void printClock(struct deltaClock* clock){
struct deltaNode* iterator;
iterator = clock->root;
while(iterator != 0){
printf("\n%d",iterator->tics);
iterator = iterator->next;
}
}
int main(int argc, char* argv[]){
printf("\nHello world.");
struct deltaClock* clock;
initDeltaClock(&clock);
push(clock, 3);
push(clock, 2);
push(clock, 7);
push(clock, 33);
push(clock, 221);
push(clock, 5);
printClock(clock);
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
printf("\npopping %d",pop(clock));
push(clock, 25);
printf("\npopping %d",pop(clock));
printf("\n");
}
答案 0 :(得分:2)
对于它的价值,这段代码运行得相当合理:
#include <stdio.h>
#include <stdlib.h>
struct deltaNode
{
int tics; // source
struct deltaNode *next;
struct deltaNode *previous;
};
struct deltaClock
{
struct deltaNode *root;
struct deltaNode *tail;
int size;
};
void initDeltaClock(struct deltaClock * *clock);
void initDeltaClock(struct deltaClock * *clock)
{
(*clock) = malloc(sizeof(struct deltaClock));
(*clock)->size = 0;
}
void push(struct deltaClock *clock, int numberOfTics);
void push(struct deltaClock *clock, int numberOfTics)
{
if (clock->root == 0)
{
// root is empty, initialize it.
clock->root = malloc(sizeof(struct deltaNode));
clock->root->tics = numberOfTics;
clock->tail = clock->root;
}
else
{
struct deltaNode *newNode = malloc(sizeof(struct deltaNode));
newNode->tics = numberOfTics;
struct deltaNode *temp = clock->root;
if (newNode->tics < temp->tics)
{
clock->root->previous = newNode;
newNode->next = clock->root;
clock->root = newNode;
}
else
{
while (newNode->tics > temp->tics)
{
if (temp->next == 0)
break;
temp = temp->next;
}
if (temp->next == 0 && newNode->tics > temp->tics)
{
clock->tail->next = newNode;
newNode->previous = clock->tail;
clock->tail = newNode;
}
else
{
temp->previous->next = newNode;
newNode->previous = temp->previous;
newNode->next = temp;
temp->previous = newNode;
}
}
}
clock->size++;
}
int pop(struct deltaClock *clock);
int pop(struct deltaClock *clock)
{
struct deltaNode *temp = clock->root;
if (temp == 0)
return -1;
int result = temp->tics;
clock->root = clock->root->next;
if (clock->root != 0)
clock->root->previous = 0;
free(temp);
clock->size--;
return result;
}
void printClock(struct deltaClock *clock);
void printClock(struct deltaClock *clock)
{
struct deltaNode *iterator;
iterator = clock->root;
while (iterator != 0)
{
printf(" %d", iterator->tics);
iterator = iterator->next;
}
putchar('\n');
}
int main(void)
{
printf("Hello world.\n");
struct deltaClock *clock;
initDeltaClock(&clock);
push(clock, 3);
push(clock, 2);
push(clock, 7);
push(clock, 33);
push(clock, 221);
push(clock, 5);
printClock(clock);
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
printf("popping %d\n", pop(clock));
push(clock, 25);
printf("popping %d\n", pop(clock));
printf("\n");
}
它产生:
Hello world.
2 3 5 7 33 221
popping 2
popping 3
popping 5
popping 7
popping 33
popping 221
popping -1
popping -1
popping -1
popping -1
popping -1
popping -1
popping 25
主要更改不是设置clock->root->previous = 0;
,除非clock->root
不为空。
辅助更改是在print语句的末尾添加换行符,并从头开始删除它们。并且列表是水平打印的,每行多个数字,而不是每行一个数字。
显示的代码使用:
完全编译gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition pl.c -o pl
需要使用函数声明来干净地编译这些选项;总的来说,这是一个好主意。另一种方法是使函数全部为静态,这也适用于单文件程序。使代码编译干净所需的唯一更改是添加函数原型并将main(int argc, char **argv)
替换为main(void)
- 做得好,这非常好。
答案 1 :(得分:2)
除了给出的其他建议外,在处理指针时,最好将它们初始化为NULL或最终值,不要让它们悬空。
例如,在initDeltaClock
中,(*clock)->root
和(*clock)->tail
未初始化。这意味着,在第一个push
调用中,即使if (clock->root == 0)
的检查也无效,因为clock->root
尚未初始化为0。
以下是建议的改进:
void initDeltaClock(struct deltaClock **clock){
(*clock) = calloc(sizeof(struct deltaClock)); /* <-- zero out entire contents after alloc */
}
同样适用于malloc
中push
的结构,您可以使用calloc
代替malloc
来确保返回的块清零,或者你应该明确地将结构的指针设置为零。
此外,如果这不仅仅是玩具项目,始终检查分配函数的返回值以检查内存不足错误。