通过函数初始化C结构体

5

我需要在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;
}

我遇到了著名的“分割错误”,于是我在GDB上进行了检查,当然,一切都失败的时刻是这一行:vector->elements = NULL;
我不知道问题出在哪里。我声明了一个向量,我想我已经正确地传递了它,但它出现了问题。我知道这可能是微不足道的,而且我可能会被一些超级程序员狂批,但是,不问则不学嘛。

1
1: 将 struct Vector* vec; 更改为 struct Vector vec;,将 initialize_vector(vec); 更改为 initialize_vector(&vec); 以传递指向结构体的指针给函数。 2: 使用 malloc() 创建一个 Vector 实例。 - Grifplex
struct 没有分配内存。 - Weather Vane
"我声明一个向量" - 不!你要声明和定义一个指向 struct Vector指针。指针并不等同于它所指向的类型!在编程中,细节至关重要!"一切都搞砸的时刻就是这一行..." - 你早就搞砸了!编译器警告不是闹着玩的!启用它们并且认真对待! - too honest for this site
2个回答

11

你没有声明一个向量,你声明了一个指向向量的指针。这个指针未初始化,因此试图取消引用它会引发未定义行为

创建一个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();

1
我已经删除了我的回答。感谢您帮助我理解。为什么对内存的引用会丢失? - cs95
1
是的,完全正确。非常感谢。顺便问一下,更好的存储方式是什么?创建一个向量,创建指向向量的指针并对其进行操作,还是将其保留为普通向量并始终通过地址传递?或者像@Coldspeed建议的那样,使用mallloc()来实际使其存在。 - user6827707
2
@Coldspeed 你正在修改一个局部变量。该修改在函数外不可见。 - dbush
1
@FrynioS 你可以让初始化函数分配并返回一个指针。请看我的编辑。 - dbush

1

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

struct Vector* vec;

声明了一个指向结构体的指针,而不是实际的结构体。指针是什么?它是一个保存地址的变量。因此,所有指针,无论是 int *、char *、char ** 还是 struct Vector *,都具有相同的大小(通常是 32 或 64 位,具体取决于体系结构)。声明指针类型仅在对指针进行间接寻址(获取存储在该内存地址中的数据)时有用。这样,在上述语句中寻址时,它的含义是:“vec 是一个可以保存 struct Vector 的地址的变量。”但此刻,vec 并没有保存有效地址。

在分配值给指针变量之前,存储在该变量中的地址是垃圾值,我们称之为未初始化的变量。在你的情况下,你将这个未初始化的地址传递给 initialize_vector(),它试图访问该地址中存储的值。但正如我们所知道的那样,那个地址是垃圾值。这导致了 seg fault 错误。

另外需要指出的一点是,在编写这样的函数时,您需要做出设计决策。您想让结构体向量存储在堆上(通过调用malloc),还是存储在栈上?堆允许更多的灵活性,但它也要求程序员仔细跟踪正在使用的指针,以避免内存泄漏,这可能会变得棘手。如果我是你,我会从存储在栈上的对象开始,然后将它们的地址传递给修改函数。这样,您就不必担心调用free()了。

是的,但是我需要使用malloc(),因为实验室的人告诉我们,我们的结构体必须动态分配:D - user6827707

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接