尝试释放链表时的 SIGABRT

SIGABRT while attempting to free a linked list

我正在研究我们的教授给我们准备即将到来的考试的一些旧课文,我 运行 解决了这个问题。

我的任务是从结构如下的文本文件中读取信息:

[十进制数],[罗马数(字符串)],[o或u(优化或未优化的罗马数)]

几千行并将该信息存储在二叉搜索树中,使用十进制数作为键。每个 b运行ch 还必须包含该数字出现的次数和遇到的各种罗马版本的列表,优化的版本位于列表的顶部。 然后释放一切。

我的代码(c):

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

struct list //list node
{
  char *rom;
  struct list *next;
};

struct branch //main tree branch
{
  int count, dec;
  struct list *list;
  struct branch *right, *left;
};

struct list *insertnode(struct list *head, char *rom, char opt) //creates a head or creates and adds a new node to the end
{
  struct list *new;
  if(!head) //if !head, make one
    {
      new = malloc(sizeof(new));
      new->rom = malloc(sizeof(char)*(strlen(rom)+1));
      strcpy(new->rom, rom);
      new->next = NULL;
      return new;
    }
  if(opt == 'o') //if the roman form is optimized, put it in front of all the others
    {
      new = malloc(sizeof(new));
      new->rom = malloc(sizeof(char)*(strlen(rom)+1));
      strcpy(new->rom, rom);
      new->next = head;
      return new;
    }
  head->next = insertnode(head->next, rom, opt); //recursive insertions
  return head;
}

struct branch *insertbranch(struct branch *root, int dec, char *rom, char opt) //creates a root or creates and adds a new branch
{
  struct branch *new;
  if(!root) //if !root, make a root...
    {
      new = malloc(sizeof(new));
      new->list = insertnode(new->list, rom, opt);
      new->dec = dec;
      new->count = 1;
      new->right=new->left=NULL;
      return new;
    }
  if(dec<root->dec) root->left = insertbranch(root->left, dec, rom, opt); //branch on the left, recursive
  else if(dec>root->dec) root->right = insertbranch(root->right, dec, rom, opt); //branch on the right, recursive
  else //if there already is such a branch, increase its count
    {
      root->count += 1;
      root->list = insertnode(root->list, rom, opt);
    }
  return root;
}

void freelist(struct list *head) //frees list 'head'
{
  struct list *tmp;
  while(head)
    {
      tmp = head;
      head = head->next;
      free(tmp->rom);
      free(tmp); // <- OFFENDING LINE
    }
  return;
}

void freetree(struct branch *root) //frees tree 'root'
{
  if(!root) return;
  freetree(root->left); //recursive!
  freetree(root->right); //and on the right
  free(root->right);
  free(root->left);
  freelist(root->list);
  free(root);
  return;
}

int main()
{
  struct branch *root;
  struct list *list;
  int dec, i=1, n;
  char rom[30], opt;
  FILE *file = fopen("rom.csv", "r");
  if(!file) //is the file even there?
    return 1;

  while(fscanf(file, "%d,%[^,],%c\n", &dec, rom, &opt)==3) //go through the file and fill tree
    root = insertbranch(root, dec, rom, opt);

  freetree(root);
  printf("Goodbye!\n");
  return 0;
}

调试后我确定了问题:在函数 "freelist" 中,当它到达命令 "free(tmp)" 时程序中止。我不知道可能是什么原因。我什至检查以确保节点头存在。

感谢您的帮助!

您没有在 insertnode()insertbranch() 中分配正确的内存量。

你需要替换这个:

new = malloc(sizeof(new));

有:

new = malloc(sizeof(*new));

这是因为new是一个指针。使用 malloc(sizeof(new)),您只分配 space 来存储指针,而不是分配必要的 space 来存储结构的内容。

以下是这些函数的正确版本:

struct list *insertnode(struct list *head, char *rom, char opt) //creates a head or creates and adds a new node to the end
{
    struct list *new;
    if(!head) //if !head, make one
    {
        new = malloc(sizeof(*new));
        new->rom = malloc(sizeof(char)*(strlen(rom)+1));
        strcpy(new->rom, rom);
        new->next = NULL;
        return new;
    }
    if(opt == 'o') //if the roman form is optimized, put it in front of all the others
    {
        new = malloc(sizeof(*new));
        new->rom = malloc(sizeof(char)*(strlen(rom)+1));
        strcpy(new->rom, rom);
        new->next = head;
        return new;
    }
    head->next = insertnode(head->next, rom, opt); //recursive insertions
    return head;
}

struct branch *insertbranch(struct branch *root, int dec, char *rom, char opt) //creates a root or creates and adds a new branch
{
    struct branch *new;
    if(!root) //if !root, make a root...
    {
        new = malloc(sizeof(*new));
        new->list = insertnode(new->list, rom, opt);
        new->dec = dec;
        new->count = 1;
        new->right=new->left=NULL;
        return new;
    }
    if(dec<root->dec) root->left = insertbranch(root->left, dec, rom, opt); //branch on the left, recursive
    else if(dec>root->dec) root->right = insertbranch(root->right, dec, rom, opt); //branch on the right, recursive
    else //if there already is such a branch, increase its count
    {
        root->count += 1;
        root->list = insertnode(root->list, rom, opt);
    }
    return root;
}

我没有仔细查看每一行代码,但看起来大部分是正确的。从我的快速浏览来看,您唯一的错误是分配的内存少于您使用的内存。写入过去分配的内存的结果是不可预测的,并且可以在程序中很晚才体现出来(例如释放内存时)。这就是为什么未定义的行为很难调试的原因:)

我发现了问题。在递归调用 freetree 之后,我尝试以 free(root->left)free(root->right) 的形式再次释放相同的内存。我现在觉得有点傻。