【问题标题】:What is wrong with my linked-list?我的链表有什么问题?
【发布时间】:2014-03-31 19:55:47
【问题描述】:
int main(int argc, char *argv[])
{
  printf("successfully started main\n");
  struct uf_list myList;
  uf_list_allocate(&myList);
  printf("successfully allocated myList\n");
  insert_node(&myList, 'c');
  printf("successfully inserted into myList\n");

  return 0;
}

...

void uf_list_allocate(struct uf_list *list)
{
  list = malloc(sizeof(struct uf_list));
  if(list == NULL)
    {fprintf(stderr, "no memory for allocate");}
  list->head = list->tail = NULL;
}
//--------------------------------------------------------------------------------------
void insert_node(struct uf_list *list, const char label)   
{
  struct uf_node *it = malloc(sizeof(struct uf_node));
  if(it == NULL)
    {fprintf(stderr, "no memory for insert");}

  it->c = label;
  it->next = NULL;                                     
  it->rep = NULL;

  if(list->head == NULL)                                //the list is empty
    { list->head = list->tail = it;}
  else
    { list->tail->next = it; list->tail = it; }

  it->rep = list->head;
}
/*----------------------------------------------------------------------------*/
struct uf_node
{
  char c;
  struct uf_node *next;
  struct uf_node *rep;
};
/*----------------------------------------------------------------------------*/
struct uf_list
{
  struct uf_node *head;
  struct uf_node *tail;
};

当我尝试将一个元素从main 插入到我的列表中时,我遇到了分段错误。 是什么导致了分段错误?如果您需要更多信息,例如structs 的定义,请告诉我!

编辑:我意识到我做了什么。在allocate里面我改了局部变量list.的地址,这意味着myList什么都没有发生。但是,现在我遇到了以下难题:我将 myList 的声明放在 main, 之外,一切正常:

struct uf_list myList;

int main(int argc, char *argv[])
{
  printf("successfully started main\n");
  uf_list_allocate(&myList);
  printf("successfully allocated myList\n");
  insert_node(&myList, 'c');
  insert_node(&myList, 'd');
  insert_node(&myList, 'e');
  printf("successfully inserted into myList\n");
  print_uf_list(&myList); 


  return 0;
} 

我不太明白为什么。似乎应该应用相同的逻辑,即,由于我将 myList 的地址传递给 allocate,然后更改局部变量 list 地址并对该地址进行操作,这如何反映在 myList 的内存地址上不是在操作吗?

【问题讨论】:

  • -1:你有 1.2k 的代表,当然你知道最好不要先做一些基本的调试就问一个关于 seg-fault 的问题。
  • 我到处都放了一堆打印语句,但没有运气......我很少用 C 编程,我所做的大部分事情都是用高级语言编写的。这里的一切对我来说似乎都是合乎逻辑的。我不知道还能做什么......
  • 单步执行,看看执行的最后一行可能是什么?列表结构的声明在哪里?问题很可能是从您没有发布的 uf_list_allocate() 开始的。
  • 顺便说一句,如果 malloc 失败,代码不应继续。最佳口头禅...
  • 是双向链表吧?所以it->rep 应该指向前一个节点而不是list->head?

标签: c linked-list segmentation-fault


【解决方案1】:

在分配中,您不会返回任何内容。达是问题所在。在 main 中,您应该只有一个指针作为局部变量,并将分配器函数返回的内容分配给它。

编辑

更简单,因为它已经分配(在 main 的堆栈上),您可以从该函数中删除分配代码,并拥有一个初始化函数。 这就是你所需要的:

  Uf_list_init(struct uf_list *list)
 {
    list->head = list->tail = NULL;
 }

在原代码中:

list = malloc(sizeof(struct uf_list));

你有一个指向 te 结构的指针,但是你用一个全新的指针覆盖它。

【讨论】:

  • 等等,我传递了myList的地址,为什么我不能更改headtail的值?
  • 我不记得确切,但这可能是标准的一部分,你可以谷歌它。但是堆栈上的变量肯定不会自动以任何值初始化,它们只是在开始时充满随机位。
  • 另请注意,NULL 指针不需要等于零,因此依赖包含 NULL 指针的零填充内存不是严格可移植的,违反最佳实践。所以请不要依赖它来学习C。
  • 无论如何,依赖它是非常糟糕的做法,分配并不是严格意义上的多余,以这种方式消除它是一个丑陋的黑客。
【解决方案2】:

C 按值传递参数。 uf_list_allocate 应该采用 uf_list **listRef 以便可以修改。

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

struct uf_node
{
  char c;
  struct uf_node *next;
  struct uf_node *rep;
};

struct uf_list
{
  struct uf_node *head;
  struct uf_node *tail;
};

void uf_list_allocate(struct uf_list **listRef)
{
  *listRef = malloc(sizeof(struct uf_list));
  if(*listRef == NULL)
    {fprintf(stderr, "no memory for allocate"); exit(0);}
  (*listRef)->head = (*listRef)->tail = NULL;
}

void insert_node(struct uf_list *list, const char label)
{
  struct uf_node *it = malloc(sizeof(struct uf_node));
  if(it == NULL)
    {fprintf(stderr, "no memory for insert"); exit(0);}

  it->c = label;
  it->next = NULL;
  it->rep = NULL;

  if(list->head == NULL)                                //the list is empty
    { list->head = list->tail = it;}
  else
    { list->tail->next = it; list->tail = it; }

  it->rep = list->head;
}

int is_empty(const struct uf_list *list)
{
  return list->head == NULL;
}

void remove_node(struct uf_list *list)
{
  if (is_empty(list))
  {
    printf("List underflow\n"); exit(0);
  }
  else
  {
    struct uf_node *oldhead = list->head;
    list->head = list->head->next;
    if (list->tail == oldhead)
      list->tail = NULL;
    free(oldhead);
    printf("Node removed\n");
  }
}

void deallocate(struct uf_list **listRef)
{
  struct uf_list *list = *listRef;
  if(!is_empty(list))
  {
    while(!is_empty(list))
      remove_node(list);
  }
  free(list);
  list = NULL;
  printf("List deallocated\n");
}

void printList(const struct uf_list *myList)
{
  struct uf_node *cur = myList->head;
  while(cur!=NULL)
  {
    printf("%c -> ", cur->c);
    cur = cur->next;
  }
  printf("\n");
}

int main(int argc, char *argv[])
{
  printf("successfully started main\n");
  struct uf_list *myList;
  uf_list_allocate(&myList);
  printf("successfully allocated myList\n");

  insert_node(myList, 'c');
  printf("successfully inserted c into myList\n");

  insert_node(myList, 'd');
  printf("successfully inserted d into myList\n");
  printList(myList);

  insert_node(myList, 'e');
  printf("successfully inserted e into myList\n");
  printList(myList);

  remove_node(myList);
  printf("successfully removed c (head) from myList\n");
  printList(myList);

  deallocate(&myList);

  return 0;
}

【讨论】:

  • 是main的栈变量,不能修改地址
  • 当然,你也应该在 main 中进行适当的更改。
  • 我刚刚将myList 的声明放在main 之外,它可以工作。为什么?全局变量在数据段中分配正确吗?
  • 你不能在函数中修改myList,除非它是一个全局变量或者它是通过引用传递的。我在remove_node(删除头节点)、deallocate(清空和释放整个列表)和更多示例中添加了一些代码。它使它更清晰一些。希望你现在得到它。我正在发布整个代码 - insert_node 没有改变,只是如果 malloc 失败,它会中止执行。
猜你喜欢
  • 1970-01-01
  • 2017-11-28
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 2018-12-23
相关资源
最近更新 更多