【问题标题】:c - generic linked listc - 通用链表
【发布时间】:2017-06-03 10:06:49
【问题描述】:

我正在尝试用 ansic (c89) 编写最简单的通用链表。

代码如下:

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

struct node {
  struct node *previous;
  struct node *next;
  void *value;
};

struct node*
allocate_node(void);

void
free_node(struct node *freeable_node);

void
init_node(struct node *initializable_node);

void
print_node(struct node *printable_node);

struct node*
allocate_node(void)
{
  struct node *allocatable_node =
    (struct node*) calloc(1, sizeof(struct node));

  allocatable_node -> previous = NULL;
  allocatable_node -> next = NULL;
  return allocatable_node;
}

void
free_node(struct node *freeable_node)
{
  free(freeable_node -> previous);
  free(freeable_node -> next);
  free(freeable_node -> value);
  free(freeable_node);
}

void
init_node(struct node *initializable_node)
{
  int *initializable_value = (int*) (initializable_node -> value);
  initializable_value = calloc(1, sizeof(int*));
  *initializable_value = rand() % 100;
}

void
print_node(struct node *printable_node)
{
  printf("%d\n", *((int*) (printable_node -> value)));
}

int
main(void)
{
  struct node *demo_list = NULL;

  srand((unsigned int) time(NULL));
  demo_list = allocate_node();
  init_node(demo_list);
  print_node(demo_list);
  free(demo_list);

  return 0;
}

通过clang编译成功,但运行后打印segfault

valgrind 输出:

$ valgrind ./build/app                                                                  
==23061== Memcheck, a memory error detector
==23061== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23061== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==23061== Command: ./build/app
==23061==
==23061== Invalid read of size 4
==23061==    at 0x4007AE: print_node (app.c:56)
==23061==    by 0x400813: main (app.c:67)
==23061==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==23061==
==23061==
==23061== Process terminating with default action of signal 11 (SIGSEGV)
==23061==  Access not within mapped region at address 0x0
==23061==    at 0x4007AE: print_node (app.c:56)
==23061==    by 0x400813: main (app.c:67)
==23061==  If you believe this happened as a result of a stack
==23061==  overflow in your program's main thread (unlikely but
==23061==  possible), you can try to increase the size of the
==23061==  main thread stack using the --main-stacksize= flag.
==23061==  The main thread stack size used in this run was 8388608.
==23061==
==23061== HEAP SUMMARY:
==23061==     in use at exit: 32 bytes in 2 blocks
==23061==   total heap usage: 2 allocs, 0 frees, 32 bytes allocated
==23061==
==23061== LEAK SUMMARY:
==23061==    definitely lost: 8 bytes in 1 blocks
==23061==    indirectly lost: 0 bytes in 0 blocks
==23061==      possibly lost: 0 bytes in 0 blocks
==23061==    still reachable: 24 bytes in 1 blocks
==23061==         suppressed: 0 bytes in 0 blocks
==23061== Rerun with --leak-check=full to see details of leaked memory
==23061==
==23061== For counts of detected and suppressed errors, rerun with: -v
==23061== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

有什么解决办法吗?

【问题讨论】:

  • 如果您想要更好的方法,请查看stackoverflow.com/questions/1885408/linux-kernels-list-h
  • "最简单的通用链表" --> 请注意void *value; 可以处理指向对象的指针,但也不能处理指向函数的指针。为此,使用void*int (*)() 中的union
  • @chux 何时应将函数指针存储在数据结构中? D.s.旨在存储数据,不是吗?
  • @LexUshakov 函数指针是数据。本质上,存储在结构中的函数指针是 C++ 中虚拟指针的基础属性。 C 中也出现了类似的需求。
  • @chux 从硬件的角度来看,常规数据和处理器指令存储在同一设备中。但是对于我们程序员来说,情况就不同了,对吧?在实践中将函数指针存储在数据结构中的用例在哪里?我真的不明白。

标签: c generics


【解决方案1】:

问题很简单,init_node 函数中少了一行。

void
init_node(struct node *initializable_node)
{
  int *initializable_value = (int*) (initializable_node -> value);
  initializable_value = calloc(1, sizeof(int*));
  *initializable_value = rand() % 100;
  //This line puts the variable you just created in the structure
  initializable_node->value=initializable_value;
}

顺便说一句,在main 函数中,我认为您的意思是使用free_node(demo_list); 而不是free(demo_list);

如果您需要更多帮助,请随时提出!

编辑:意识到不需要init_node 函数的第一行,因为您正在为int 指针分配一个NULL 值。

因此,请这样做:

void
init_node(struct node *initializable_node)
{
  int *initializable_value = calloc(1, sizeof(int*));
  *initializable_value = rand() % 100;
  //This line puts the variable you just created in the structure
  initializable_node->value=initializable_value;
}

【讨论】:

  • 谢谢!我考虑了一下)但是,正如我所理解的,*initializable_value 将值的地址存储在堆中,并且它指向与initializable_node -&gt; value 相同的地址,为什么它不是真的?为什么我们应该做额外的分配?
  • 查看编辑,这是不正确的,因为initializable_node-&gt;value 为 NULL,因此他的地址是垃圾。只有当您执行calloc 功能时,您才有真实地址。所以只有这样你才能分配你分配给结构的地址。
  • 你说得对,我已经明白了。我为我的愚蠢问题感到羞耻。
【解决方案2】:

free(freeable_node -&gt; value);
这个void * value 永远不会被初始化。所以value 默认情况下会有垃圾值,你正在尝试释放该内存。

【讨论】:

  • 但是在main 中的init_node 之后插入了free_node
  • @LexUshakov init_node() 没有按照您的代码初始化值。
猜你喜欢
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多