代码之家  ›  专栏  ›  技术社区  ›  mytosus

尝试访问结构中的空指针时出现Segfault

  •  0
  • mytosus  · 技术社区  · 8 年前

    好的,所以我要用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;
    }
    

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

    3 回复  |  直到 8 年前
        1
  •  2
  •   R Sahu    8 年前

    线路

    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* 但您正在尝试分配 整数 这是一个很好的例子。
    4. 您正在存储函数局部变量的地址 i 在一个 struct 这将从函数返回。当函数返回时,将有一个悬空指针。

    您需要:

    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
  •  2
  •   Jack    8 年前

    这里有两级分配。 vector->nodes 是一个 vector_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;
    

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

        3
  •  1
  •   Ziffusion    8 年前

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

    更改的定义 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 。因为内存包含对象而不是指向对象的指针,所以需要直接偏移指针才能到达各个对象。