好的,所以我正在进行一项任务,你必须在C中构建一个循环双端队列。我已经实现了所有的功能,我正在测试它们。一切都很好,直到'反向'功能。
我认为这很容易,你创建了一个新链接,将其连接起来代替Sentinel。杀死旧的哨兵,然后将deque的哨兵设置为新的链接。
然而,当我运行这个时,我得到一个malloc错误,因为我是C的新手,我不知道如何调试。
-------- ERROR -------
对象0x7faf13c03920的码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#include "cirListDeque.h"
/* Double Link Struture */
struct DLink {
TYPE value;/* value of the link */
struct DLink *next;/* pointer to the next link */
struct DLink *prev;/* pointer to the previous link */
};
# define TYPE_SENTINEL_VALUE DBL_MAX
/* ************************************************************************
Deque ADT based on Circularly-Doubly-Linked List WITH Sentinel
************************************************************************ */
struct cirListDeque {
int size;/* number of links in the deque */
struct DLink *Sentinel; /* pointer to the sentinel */
};
/* internal functions prototypes */
struct DLink* _createLink (TYPE val);
void _addLinkAfter(struct cirListDeque *q, struct DLink *lnk, struct DLink *newLnk);
void _removeLink(struct cirListDeque *q, struct DLink *lnk);
/* ************************************************************************
Deque Functions
************************************************************************ */
/* Initialize deque.
param: q pointer to the deque
pre: q is not null
post: q->backSentinel is allocated and q->size equals zero
*/
void _initCirListDeque (struct cirListDeque *q)
{
struct DLink* lnk = (struct DLink*)malloc(sizeof(struct DLink));
assert(lnk != 0); //sentinel made
q->Sentinel = lnk;
q->Sentinel->next = q->Sentinel->prev = q->Sentinel;
q->size = 0;
}
/*
create a new circular list deque
*/
struct cirListDeque *createCirListDeque()
{
struct cirListDeque* newCL = malloc(sizeof(struct cirListDeque));
_initCirListDeque(newCL);
return(newCL);
}
/* Create a link for a value.
param: val the value to create a link for
pre: none
post: a link to store the value
*/
struct DLink * _createLink (TYPE val)
{
struct DLink* lnk = (struct DLink*) malloc(sizeof(struct DLink));
lnk->value = val;
return(lnk);
}
/* Adds a link after another link
param: q pointer to the deque
param: lnk pointer to the existing link in the deque
param: newLnk pointer to the new link to add after the existing link
pre: q is not null
pre: lnk and newLnk are not null
post: the new link is added into the deque after the existing link
*/
void _addLinkAfter(struct cirListDeque *q, struct DLink *lnk, struct DLink *newLnk)
{
lnk->next->prev = newLnk; //right connects to new
newLnk->next = lnk->next; //new connect to right
newLnk->prev = lnk; //new connect to left
lnk->next = newLnk; //left connect to new
q->size++;
}
/* Adds a link to the back of the deque
param: q pointer to the deque
param: val value for the link to be added
pre: q is not null
post: a link storing val is added to the back of the deque
*/
void addBackCirListDeque (struct cirListDeque *q, TYPE val)
{
struct DLink* lnk = _createLink(val);
_addLinkAfter(q, q->Sentinel->prev, lnk);
}
/* Adds a link to the front of the deque
param: q pointer to the deque
param: val value for the link to be added
pre: q is not null
post: a link storing val is added to the front of the deque
*/
void addFrontCirListDeque(struct cirListDeque *q, TYPE val)
{
struct DLink* lnk = _createLink(val);
_addLinkAfter(q, q->Sentinel, lnk);
}
/* Get the value of the front of the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: none
ret: value of the front of the deque
*/
TYPE frontCirListDeque(struct cirListDeque *q)
{
return q->Sentinel->next->value;
}
/* Get the value of the back of the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: none
ret: value of the back of the deque
*/
TYPE backCirListDeque(struct cirListDeque *q)
{
return q->Sentinel->prev->value;
}
/* Remove a link from the deque
param: q pointer to the deque
param: lnk pointer to the link to be removed
pre: q is not null and q is not empty
post: the link is removed from the deque
*/
void _removeLink(struct cirListDeque *q, struct DLink *lnk)
{
//assert(!isEmptyList(lst));
lnk->next->prev = lnk->prev; //connect right link to left link
lnk->prev->next = lnk->next; //connect left link to right link
q->size--;
free(lnk);
}
/* Remove the front of the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: the front is removed from the deque
*/
void removeFrontCirListDeque (struct cirListDeque *q) {
_removeLink(q, q->Sentinel->next);
}
/* Remove the back of the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: the back is removed from the deque
*/
void removeBackCirListDeque(struct cirListDeque *q)
{
_removeLink(q, q->Sentinel->prev);
}
/* De-allocate all links of the deque
param: q pointer to the deque
pre: none
post: All links (including backSentinel) are de-allocated
*/
void freeCirListDeque(struct cirListDeque *q)
{
while (q->size > 0){
removeFrontCirListDeque(q);
}
free(q->Sentinel);
}
/* Check whether the deque is empty
param: q pointer to the deque
pre: q is not null
ret: 1 if the deque is empty. Otherwise, 0.
*/
int isEmptyCirListDeque(struct cirListDeque *q) {
return q->size == 0;
}
/* Print the links in the deque from front to back
param: q pointer to the deque
pre: q is not null and q is not empty
post: the links in the deque are printed from front to back
*/
void printCirListDeque(struct cirListDeque *q)
{
struct DLink *current;
int x = 0;
assert(!isEmptyCirListDeque(q));
current = q->Sentinel->next;
while(current != q->Sentinel){
printf("value: %f\t", current->value);
current = current->next;
x++;
if (x >= 6){
printf("\n");
x = 0;
}
}
}
/* Reverse the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: the deque is reversed
*/
void reverseCirListDeque(struct cirListDeque *q)
{
//struct DLink *temp = _createNewLink(0); //try this allocat then assign then move
struct DLink *newSent = (struct DLink*) malloc(sizeof(struct DLink));
newSent->next = q->Sentinel->prev;
newSent->prev = q->Sentinel->next;
q->Sentinel->next->prev = newSent;
q->Sentinel->prev->next = newSent;
free(q->Sentinel);
q->Sentinel = newSent;
/* A different approach that didn't work.
temp->next = q->Sentinel->prev;
q->Sentinel->prev = q->Sentinel->next;
q->Sentinel->next = temp->next;
free(temp);*/
}
答案 0 :(得分:1)
对于调试C程序, gdb 是最好的。学习如何使用它对你有很大好处。文档位于http://sourceware.org/gdb/current/onlinedocs/gdb/
如果你真的想要一个GUI前端(并且“gdb -tui”是不可接受的),请尝试 ddd 或洞察力。
调试器将帮助您在程序运行时继续使用,并使您能够在每一步检查数据结构,以便在第一次损坏时找到它们。
答案 1 :(得分:0)
我调试它的方法是添加printfs。例如,在_initCirListDeque
中调用malloc之后添加:
fprintf(stderr, "dbg malloc sentinel %p\n", (void *)lnk);
在reverseCirListDeque
中的malloc之后添加一个类似的行。
然后在_removeLink
,freeCirListDeque
和reverseCirListDeque
的免费调用之前添加类似的printf行。
当您运行代码时,您应该在标准错误上看到指针地址被malloc'd和释放。您应该能够看到未释放的值是否已经被释放(我的猜测是这就是正在发生的事情)。
单词dbg
的目的是让您轻松搜索这些调试printfs并在发现错误后将其删除。
答案 2 :(得分:0)
我在这里回答了我自己的问题,但是由于这些海报,调试技巧使这个答案成为可能。
我的逻辑存在缺陷。
我认为如果你改变了哨兵的方向,你可以颠倒循环清单的顺序。但是,即使您将所有四个链接更改为标记,周围链接prev和next字段也指向错误的方向。
为了解决这个问题,我使用以下代码创建了一个新的双端队列:
void reverseCirListDeque(struct cirListDeque *q)
{
struct cirListDeque* newQ = createCirListDeque();
while(!isEmptyCirListDeque(q)){
addBackCirListDeque(newQ, backCirListDeque(q));
removeBackCirListDeque(q);
}
q->Sentinel = newQ->Sentinel;
q->size = newQ->size;
free(newQ);
}