【问题标题】:Initialize C struct through a function通过函数初始化 C 结构
【发布时间】:2017-06-15 18:50:19
【问题描述】:

所以我必须在 C 中编写一个类似vector 的数据结构。一般我做了一个这样的结构:

struct Vector
{
    int length;
    int *elements;
};

还有这样的功能:

void initialize_vector(struct Vector* vector);
void create_vector(struct Vector* vector, int* array, int n);
void remove_vector(struct Vector* vector);
void vector_add_element(struct Vector* vector, int element);
void vector_insert(struct Vector* vector, int index, int element);
void vector_remove_element(struct Vector* vector, int element);
void vector_remove_at(struct Vector* vector, int index);

现在,initialize_vector() 函数,我希望它只是将向量属性初始化为默认值(例如 length 为 0 和 *elements 为 NULL)。我写了这样的东西:

void initialize_vector(struct Vector* vector)
{
    vector->elements = NULL;
    vector->length = 0;
}

我试着检查它是否有效,所以我写了这段代码:

#include <stdio.h>
#include "vector.h"


int main(int arc, char** argv)
{
    struct Vector* vec;
    initialize_vector(vec);
    printf("%d\n", vec->length);
    return 0;
}

我得到了著名的Segmentation fault,所以我检查了 GDB,当然,所有事情都搞砸的那一刻是这行:vector-&gt;elements = NULL;

我不知道问题出在哪里。我声明了一个向量,我猜我正确地传递它并且它搞砸了。我知道这可能是微不足道的,我会被一些超级程序员大大否决,但是,嘿,他什么都不质疑什么都学。

【问题讨论】:

  • 1:将 struct Vector* vec; 更改为 struct Vector vec; initialize_vector(vec);initialize_vector(&amp;vec); 以向函数传递指向结构的指针。 2:使用 malloc() 为 Vector 创建一个实例。
  • 没有为struct分配内存。
  • "我声明了一个向量" - 不!您声明并定义了一个指向struct Vector指针。指针与其指向的类型不同!细节在编程中很重要! “一切搞砸的那一刻就是这条线......” - 你搞砸了!编译器警告不是为了好玩!启用它们并注意!

标签: c pointers struct


【解决方案1】:

你没有声明一个向量,你声明了一个指向向量的指针。该指针未初始化,因此尝试取消引用它会调用undefined behavior

创建一个struct Vector 并传递它的地址:

struct Vector vec;
initialize_vector(&vec);
printf("%d\n", vec.length);

如果你想同时为一个struct Vector分配空间,把函数改成调用malloc并返回指针:

struct Vector *initialize_vector()
{
    struct Vector *vector = malloc(sizeof(*vector));
    if (!vector) {
        perror("malloc failed");
        exit(1);
    }
    vector->elements = NULL;
    vector->length = 0;
    return vector;
}

...

struct Vector *vector = initialize_vector();

【讨论】:

  • 我已经删除了我的答案。谢谢你帮助我理解。为什么对内存的引用会丢失?
  • 是的,完全正确。完美运行,谢谢。顺便说一句,有什么更好的方法来存储它,创建一个向量,创建指向向量的指针并对其指针进行操作,或者只是将其保留为普通向量并始终通过地址传递它?或者正如@Coldspeed 建议的那样,使用mallloc() 使其存在
  • @Coldspeed 您正在修改一个局部变量。该修改在函数之外不可见。
  • @FrynioS 您可以让初始化函数分配并返回一个指针。查看我的编辑。
【解决方案2】:

dbush 给出了一个很好的答案,所以我不会给你代码。相反,我将给出一点 C 指针解释,这样您就不会再次遇到同样的错误。

struct Vector* vec;

声明指向结构的指针,而不是实际的结构。指针到底是什么?它是一个保存地址的变量。因此,所有指针,无论它们是 int *、char *、char ** 还是 struct Vector *,都具有相同的大小(通常为 32 位或 64 位,具体取决于架构)。声明指针的类型仅对取消引用指针有用(获取存储在该内存地址中的数据)。因此,取消引用 void * 指针会导致错误是有道理的。回到上面的声明,用英文,这个声明是这样写的:“vec 是一个变量,可以保存一个 struct Vector 的地址。”然而,此时 vec 没有有效的地址。

在您为指针变量赋值之前,该变量中存储的地址是垃圾,我们称其为未初始化变量。在您的情况下,您然后将此未初始化的地址传递给 initialize_vector(),它试图访问存储在该地址中的值。但正如我们所知,那个地址是垃圾。这给出了段错误。

要指出的另一件事是,在编写此类函数时,您需要做出设计决策。您希望 struct Vectors 存在于堆上(通过调用 malloc)还是栈上?堆允许更大的灵活性,但它也需要程序员仔细跟踪正在使用的指针以避免内存泄漏,这可能会变得很棘手。如果我是你,我会从堆栈中的对象开始,然后将它们的地址传递给修改函数。 dbush 的第一个答案。这样您就不必担心调用 free()。

【讨论】:

  • 是的,但是我需要malloc()s,因为实验室的人告诉我们,我们的结构必须动态分配:D
猜你喜欢
  • 2021-03-17
  • 1970-01-01
  • 2020-08-31
  • 2020-05-31
  • 2019-05-24
  • 1970-01-01
  • 2016-12-22
  • 2017-06-23
  • 2012-09-15
相关资源
最近更新 更多