在C语言中分配内存的困惑

3

我很努力地寻找相关信息,但仍然无法理解。假设我有一个结构体:

struct some_struct {
    int x;
    int y;
    char *some_string;
};

假设我们有上面的结构体,如何为该结构体分配一些内存?可以简单地执行以下操作:
struct some_struct *test_struct;
test_struct = malloc(sizeof(struct some_struct));

但这样就足够了吗?您不需要为some_string分配一些内存吗?或者如果结构体包含更多指针,您也不需要为它们分配内存吗? 编辑:还有一件事...假设我的结构体some_struct已经有数据了,例如:
struct some_struct *test_struct = malloc(sizeof(some_string);
test_struct->x = 2;
test_struct->y = 3;
test_struct->some_string = "sadlfkajsdflk";

以下代码足以释放已分配的内存吗?
free(test_struct);

还是需要我自己去释放 char* 变量 some_string 吗?
谢谢。

1
关于编辑,您让 test_struct->some_string 指向一个字符串字面量,而不是指向内存 (m|c|re)alloc,因此在这种情况下不应该 free 它。但如果您已经为 test_struct->some_string 分配了内存 (m|c|re)alloc,则在 free test_struct 之前应该先 free 它,否则会造成内存泄漏。 - Daniel Fischer
4个回答

6

调用malloc(sizeof(struct some_struct));可以为您的结构体分配内存,其中包括两个整数字段和一个指针字段的空间。

然而,指针字段在指向有效的内存位置之前不能使用。为了做到这一点,您需要将其指向一个有效的内存位置,例如通过使用malloc为其分配内存或将其指向一个预先存在的有效内存位置:

例如:

test_struct->some_string = malloc(100); // Allocate 100 bytes for the string

你好,我想知道您是否可以对我的新编辑问题发表评论,谢谢 :) - chutsu
2
@chutsu,使用malloc分配的任何内容都必须使用free()释放。因此,如果您使用malloctest_struct->some_string分配内存,则必须使用free释放它。但是在您的示例代码中,您只是将test_struct设置为字符串文字,这意味着您不需要释放它。 - Charles Salvia

2
在运行以下两行代码后:
struct some_struct *test_struct;
test_struct = malloc(sizeof(struct some_struct));

你已经做足了与 test_struct 一起工作的准备。指针的值只是一个内存地址,所以 malloc 分配了足够的空间来存储两个 int 和一个 char*。如果你想将 test_struct->some_string 指向已经存在的 char*,你可以这样做:

test_struct->some_string = some_other_char_pointer;

否则,您还需要为其分配内存:
test_struct->some_string = malloc(...);

1

好的,这段代码没有实现你想要的功能:

struct some_struct *test_struct = malloc(sizeof(some_string);
test_struct->x = 2;
test_struct->y = 3;
test_struct->some_string = "sadlfkajsdflk";

在这种情况下,你的*test_struct现在指向一个具有some_string大小的'memory zone'(我认为你的some_string是char*)。 Malloc(X)从程序(或进程)虚拟内存中给你分配了X的空间。 当你执行:
struct some_struct *test_struct; 

您有足够的空间来存储指向 some_struct 的指针。

如果您执行以下操作:

malloc(sizeof(struct some_struct));

您现在已经从虚拟内存中保留了struct some_struct的空间。但是您想知道这个内存的“位置”。这就是为什么您将其分配给指针的原因:

test_struct = malloc (sizeof(struct some_struct));

[编辑]我会这样写:“为了让编译器更加愉快,你还应该在其中包含一个转换,告诉编译器malloc分配的空间将用于存储struct some_struct:”,并在之后给出一个示例。但实际上,这是不正确的。正如您在下面的评论中所看到的,@chutsu进行了更正,并且为了让自己相信,请查看question。 主要原因是你冒很大的风险,而没有任何好处。
代码的其余部分现已更正:无需转换。

更清晰的方法是对结构体进行typedef。然后,您的代码将如下所示:

typedef struct some_struct {
    int x;
    int y;
    char *some_string;
}SomeStruct;

SomeStruct *test_struct;
test_struct = malloc(sizeof(SomeStruct));

关于字符串分配。你可以这样想:使用malloc(以及它的兄弟函数calloc,realloc等)创建的所有内容都需要释放!这是因为所有其他变量都是函数本地变量,即使主函数也是一个函数,在函数终止时会被清除。
因此,在分配结构体后,如果您想要为字符串腾出空间,您必须为其分配空间。
test_struct->some_string = malloc((YOUR_STRING_SIZE+SPACE_FOR_THE_STRING_TERMINATOR)*sizeof(char));

使用 - SPACE_FOR_THE_STRING_TERMINATOR=1,即\0字符。

然后,如果你想释放test_struct,你必须先释放字符串,然后再释放结构体,以相反的顺序。否则你会失去指向字符串的指针,导致内存泄漏。 具体如下:

free(test_struct->some_string);
free(test_struct);

就是这样,你完成了。

希望这有所帮助。


实际上,在C语言中,您不需要在malloc前面加上强制类型转换。请看我在这里写的文章:http://chutsu.tumblr.com/post/38958361088/do-not-add-a-cast-to-malloc-when-programming-in-c - chutsu
我从那份文件中得到的信息是,如果你忘记包含,就不应该进行强制类型转换?通常我会进行强制类型转换,因为我知道它返回的是那种类型。[编辑]顺便说一句,Tumblr很棒。 - Afonso Tsukamoto
不,应该反过来,你不应该进行强制类型转换,因为你可能会忘记包含头文件。诚然,链接的措辞很糟糕。但基本上,如果你在 C 编译器中进行了强制类型转换,编译器会认为你知道自己在做什么。问题是,如果你忘记了 #include <stdlib.h>,并且在 malloc 前面加了一个强制类型转换,编译器不会告诉你忘记包含 stdlib,而是给出其他无用的错误信息。看看这个问题吧 :) - chutsu
1
啊!好的。实际上,这让我很有道理。你在这里学到的这种东西实际上非常棒!:) 我的任何一位老师都没有提到过这样的事情,他们总是提到像“编写更少的代码是避免错误的最佳方法”这样的东西,并指出所有良好的编程实践。非常感谢@chutsu。我得编辑我的答案。 - Afonso Tsukamoto

1

根据上下文,您可能需要为字符串分配一些内存,也可能不需要。但是您提供的代码会分配所有需要容纳该结构的内存。

基本上,编写代码以执行所需的任何操作。是否需要为字符串分配内存取决于您要执行的操作。

仅凭您展示的代码,您分配的指针并没有指向任何特定的内容,就像您分配的整数没有保存任何特定的值一样。如果需要为字符串分配地址,则在将some_string的值设置为有用的内容时进行,可能与将xy设置为有用的内容同时进行。


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