尝试访问结构中的void指针时的Segfault

时间:2016-01-28 02:48:06

标签: c memory data-structures segmentation-fault void-pointers

好吧我正在c中制作矢量数据结构(或动态列表)。 这是我的节点结构:

struct vector_node{
  void *value;
};

这是我的矢量结构:

struct vector{
  int size;
  int capacity;
  vector_node *start;
  vector_node *end;
  vector_node **nodes;
};

这是我如何创建和分配向量的内存:

vector* createVector(){
  vector *vector = malloc(sizeof(vector));
  vector->size = 0;
  vector->capacity = 8;
  vector->start = NULL;
  vector->end = NULL;
  vector->nodes = malloc(8*sizeof(vector_node));
  int i = 0;
  vector->nodes[0]->value = (int) &i;
}

最后两行是我遇到麻烦的地方。似乎每当我尝试初始化值变量时,我都会遇到段错误。

3 个答案:

答案 0 :(得分:2)

这里有两级分配。 vector->nodesvector_node**,因此通过取消引用它,您将获得vector_node*,您尝试通过->value连续取消引用以获取实例的字段。

但是你如何分配一切? nodes包含指针而不是真实对象,因此在为指针分配空间之后,还必须单独分配每个节点。

所以分配应该是这样的:

const size_t LENGTH = 8;
vector->nodes = malloc(LENGTH * sizeof(vector_node*)); // note it's vector_node* not vector_node, as we're allocating memory for pointers
for (size_t i = 0; i < LENGTH; ++i)
  vector->nodes[i] = malloc(sizeof(vector_node)); // here we're allocating the real object

// now you can correctly have two chained dereferences
vector->nodes[0]->value = (int)&i;

请注意,重新分配也需要两个步骤,顺序相反。

答案 1 :(得分:2)

该行

vector->nodes = malloc(8*sizeof(vector_node));

错了。您需要分配一个vector_node*数组,因为vector->nodes类型为vector_node**。避免此类错误的推荐方法是:

Type* x = malloc(count*sizeof(*x));

对于您的计划,将是:

vector->nodes = malloc(8*sizeof(*(vector->nodes)));

该行

vector->nodes[0]->value = (int) &i;

有几个错误。

  1. 在尝试取消引用之前,您尚未为vector->nodes[0]分配内存。
  2. 您正在将指针转换为int,这可能会导致地址被截断。
  3. vector->nodes[0]->value的类型为void*,但您正在尝试为其分配int
  4. 您正在将函数本地变量i的地址存储在将要从函数返回的struct中。当函数返回时,你将有一个悬空指针。
  5. 你需要:

    vector->nodes[0] = malloc(sizeof(*(vector->nodes[0])));
    vector->nodes[0]->value = <some memory that will outlast the function call>;
    

    最后,在返回类型不同于return的函数中,您没有void语句。如果调用代码使用类似:

    vector* v = createVector();
    

    您的程序将显示未定义的行为。

答案 2 :(得分:1)

要处理您的想法,您需要做一些事情。

更改vector的定义如下:

struct vector{
  int size;
  int capacity;
  vector_node *start;
  vector_node *end;
  vector_node *nodes; // <----- this is a pointer that can be offset like an array
};

更改createVector()的定义,如下所示:

vector* createVector(){
  vector *vector = malloc(sizeof(vector));
  vector->size = 0;
  vector->capacity = 8;
  vector->start = NULL;
  vector->end = NULL;
  vector->nodes = malloc(8*sizeof(vector_node));
  int i = 0;
  vector->nodes[0].value = (void*) &i; // <----- offset the pointer like an array
                                       // <----- (which is what you allocated for)
}

原因是您为8个vector_node类型的对象分配了内存,并将基指针分配给vector->nodes。因为内存包含对象而不是指向对象的指针,所以需要直接偏移指针以获取单个对象。