使用链表的斐波那契数列在链表被销毁后崩溃。如何追踪错误?

时间:2018-07-02 18:39:39

标签: c

我正在开发一个程序,该程序可以在不使用int数据类型的情况下计算斐波那契数列中的任何数字,因为它会溢出。相反,我使用链接列表来保存代表每个数字的数字。我当前的问题是释放分配给不再需要的链表的内存。如果要计算F(10000),则希望释放成千上万个以前的列表。程序按原样生成每个值,直到崩溃并显示“退出状态-1”,直到“ F(7)= 13”。我真的很想知道是什么导致此错误,然后从那里继续。任何帮助表示赞赏。谢谢您,我为其中的大量代码表示歉意。

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
int digit;
struct Node *next;
} Node;

typedef struct ListyInt
{
Node *head;
int length;
} ListyInt;



Node *create_node(unsigned int digit, ListyInt *listy);
Node *removeNode(Node *node, ListyInt *listy);
void listyPrintHelper(Node *current);
ListyInt *destroyListyInt(ListyInt *listy);
ListyInt *fib(unsigned int n);



void listyPrint(ListyInt *p)
{
if (p == NULL || p->head == NULL)
{
    printf("(null pointer)\n");
    return;
}

listyPrintHelper(p->head);
printf("\n");
}

void listyPrintHelper(Node *current)
{
if (current == NULL)
    return;

listyPrintHelper(current->next);
printf("%d", current->digit);
}

int main()
{
 int i;
 ListyInt *p;

for (i = 0; i <= 1000; i++)
{
    printf("F(%d) = ", i);
    listyPrint(p = fib(i));
    destroyListyInt(p);
}

 return 0;
}

ListyInt *listyAdd(ListyInt *p, ListyInt *q)
{
 ListyInt *listy = NULL;
 Node *ptemp = NULL;
 Node *qtemp = NULL;
 Node *temp = NULL;
 ListyInt *temp_list = NULL;
 unsigned int x = 0;
 unsigned int count = 0;

 if (p == NULL || q == NULL)
{
  return NULL;
}

 listy = malloc(sizeof(ListyInt));

 if (listy == NULL)
{
  return NULL;
}

listy->length = 0;

if (q->length > p->length)
{
temp_list = q;
q = p;
p = temp_list;
}

 while (count < p->length)
 {
  if (count == 0)
  {
  x = p->head->digit + q->head->digit;
  ptemp = p->head->next;
  qtemp = q->head->next;
  listy->head = create_node(x, listy);
  temp = listy->head;
  temp->next = create_node(0, listy);

  if (temp->digit > 9)
  {
    temp->digit = temp->digit - 10;
    temp->next->digit = temp->next->digit + 1;
   }
 }

else
{
  temp->next->next = create_node(0, listy);

  if (qtemp == NULL)
  {
    temp->next->digit += ptemp->digit;
    ptemp = ptemp->next;
    temp = temp->next;
  }

  else
  {
    x = ptemp->digit + qtemp->digit;
    temp->next->digit += x;

    if (temp->next->digit > 9)
    {
      temp->next->digit = temp->next->digit - 10;
      temp->next->next->digit = temp->next->next->digit + 1;
    }

    qtemp = qtemp->next;
    ptemp = ptemp->next;
    temp = temp->next;
   }
 }

 if (count == p->length - 1 && temp->next->digit == 0)
 {
   temp->next = removeNode(temp->next, listy);
 }

  count++;
 }

return listy;
}

ListyInt *destroyListyInt(ListyInt *listy)
{
  if (listy == NULL)
  {
    return NULL;
  }

Node *current = listy->head;
Node *temp;

while (current != NULL)
{
    temp = current->next;
    free(current);
    current = temp;
}

    free(listy);

return NULL;
}

ListyInt *fib(unsigned int n)
{
  ListyInt *spiral = malloc(sizeof(ListyInt));
  ListyInt *p = NULL;
  ListyInt *q = NULL;
  unsigned int count = 2;

  if (spiral == NULL)
  {
    return NULL;
  }

  if (n == 0)
  {
    spiral->head = create_node(0, spiral);
    return spiral;
  }

 if (n == 1)
 {
    spiral->head = create_node(1, spiral);
    return spiral;
 }

 p = malloc(sizeof(ListyInt));
 p->head = create_node(0, p);

 q = malloc(sizeof(ListyInt));
 q->head = create_node(1, q);

 while (count <= n)
 {
    spiral = listyAdd(p, q);
    destroyListyInt(p);
    p = q;
    q = spiral;
    count++;
  }

 return spiral;
}

Node *create_node(unsigned int digit, ListyInt *listy)
{
  if (listy == NULL)
  {
    return NULL;
  }

  Node *new_node = malloc(sizeof(Node));

  new_node->digit = digit;
  new_node->next = NULL;

  listy->length++;

  return new_node;
}

Node *removeNode(Node *node, ListyInt *listy)
{
  if (node == NULL)
  {
    return NULL;
  }

  if (listy == NULL)
  {
    return NULL;
  }

  free(node);
  node = NULL;
  listy->length--;
  return NULL;
}

2 个答案:

答案 0 :(得分:4)

  

我真的很想知道导致此错误的原因并从那里去。

长话短说,据我所知,C相当于NullPointerException

长话大说,我还没有时间充分检查您的代码或对其进行调试,但是我有时间通过​​gdb(大多数Linux安装中都包含)运行它。如果您使用的是Visual Studio,我隐约记得有一个调试模式,该调试模式应该在不同的地方向您显示大致相同的信息。这是GDB的输出:

Starting program: /home/ubuntu/C/a.out 
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13

Program received signal SIGSEGV, Segmentation fault.
0x00000000004008db in listyAdd (p=0x6036a0, q=0x6036e0) at main.c:117
117         temp->next->digit += ptemp->digit;

(好的,这还不是全部,但这是相关的。)

最后三行表示您得到了segfault。有很多原因可以导致它,但是基于该行,它似乎是由于尝试取消引用无效指针而引起的。要么是NULL指针(值为0x0),要么是您已经free d指向的指针。

如果您使用的是Linux,则可以在其上运行Valgrind来确定发生了什么。它会告诉您是使用free d指针还是NULL指针,这将为您找到实际的错误提供一个很好的起点。您还可以使用IDE的调试器(或GDB,如果您想尝试使用命令行版本,但我不建议这样做)来逐步执行程序,并查看所涉及变量的值是什么,可以向后走,看看它们在哪里被更改和失效了。

但是,如果我不得不猜测的话,我会说0andriy的评论hit之以鼻-您似乎要释放两次,最后可能要释放一次。

我有点故意离开这个模糊的地方。段故障很常见,并且(如您所注意到的)很难调试,您只能通过经验真正地学习如何操作。我认为,显示答案实际上不会比自己亲自解决问题有用,并且使用Valgrind和调试器之类的工具实际上并不那么困难,只是乏味。

答案 1 :(得分:0)

我发现了问题。这是因为调用fib()时未重置链接列表的长度。谢谢大家的帮助。