尝试访问结构中的空指针时出现段错误
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;
有几处是错误的。
- 在尝试取消引用之前,您还没有为
vector->nodes[0]
分配内存。
- 您正在将指针转换为
int
,这可能会导致地址被截断。
vector->nodes[0]->value
的类型是 void*
,但您正试图为其分配一个 int
。
- 您正在将函数局部变量
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
。因为内存中包含对象而不是指向对象的指针,所以需要直接偏移指针才能到达各个对象。
好吧,我正在用 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;
有几处是错误的。
- 在尝试取消引用之前,您还没有为
vector->nodes[0]
分配内存。 - 您正在将指针转换为
int
,这可能会导致地址被截断。 vector->nodes[0]->value
的类型是void*
,但您正试图为其分配一个int
。- 您正在将函数局部变量
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
。因为内存中包含对象而不是指向对象的指针,所以需要直接偏移指针才能到达各个对象。