尝试访问结构中的空指针时出现段错误

Segfault when trying to access a void pointer within a structure

好吧,我正在用 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;
}

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

这里有一个 two-level 分配。 vector->nodes 是一个 vector_node**,所以通过解引用它你得到一个 vector_node*,你尝试通过 ->value 连续解引用以获得真实实例的字段。

但是你是如何分配所有东西的? nodes 包含 指针 而不是真正的对象,因此在为指向节点的指针分配 space 之后,您还必须单独分配每个节点。

所以分配应该是这样的:

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;

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

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 中,该变量将从函数 return 编辑。当函数 returns 时,你将有一个悬空指针。

你需要:

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

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

vector* v = createVector();

您的程序将表现出未定义的行为。

要实现您的想法,您需要做几件事。

改变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)
}

这是因为你为vector_node类型的8个对象分配了内存,并将基指针分配给了vector->nodes。因为内存中包含对象而不是指向对象的指针,所以需要直接偏移指针才能到达各个对象。