[英]Not sure whether or not to malloc memory for a struct
Suppose I have the following C code: 假设我有以下C代码:
#include <stdio.h>
#include <stdlib.h>
#define NUM_PEOPLE 24
typedef struct {
char **name;
int age;
} person_t;
void get_person_info(person_t *person);
int main(int argc, char **argv) {
for (int i = 0; i < NUM_PEOPLE; i++) {
person_t new_person;
get_person_info(&new_person);
}
return 0;
}
where get_person_info()
just fills out the person_t
struct to which a pointer is passed in. Is it necessary to malloc()
memory for new_person
within main()
? 其中,
get_person_info()
仅填充将指针传递到的person_t
结构。是否有必要在main()
为new_person
malloc()
内存? That is, should the line 也就是说,该行
person_t new_person;
instead be 而是
person_t *new_person = (person_t *) malloc(sizeof(person_t));
and then change get_person_info()
to accept a person_t **
instead of a person_t *
? 然后将
get_person_info()
更改为接受person_t **
而不是person_t *
?
Sorry if this question is confusing -- I'm not sure whether or not this is a case where it is necessary to reserve memory, given that a pointer to that memory is passed into get_person_info()
to avoid causing a segmentation fault. 很抱歉,如果这个问题令人困惑-我不确定是否需要保留内存,因为指向该内存的指针已传递给
get_person_info()
以避免引起分段错误。
Both are correct, it depends on where you want to use the person_info
. 两者都是正确的,这取决于您要在何处使用
person_info
。 Allocating on the stack : 在堆栈上分配:
for (int i = 0; i < NUM_PEOPLE; i++) {
person_t new_person;
get_person_info(&new_person);
}
Creates a person_t
object on the stack and fills the new_person
object with data, because the loop only does that, the object goes out of scope on the next loop iteration and the data is lost. 在堆栈上创建一个
person_t
对象,并用数据填充new_person
对象,因为循环仅这样做,该对象在下一次循环迭代时超出范围,并且数据丢失。
Using malloc : 使用malloc:
for (int i = 0; i < NUM_PEOPLE; i++) {
person_t *new_person = malloc(sizeof(person_t));
get_person_info(new_person);
}
Creates a person_t
object on the heap and fills it with data, because its allocated on the heap the new_person
object will outlive the loop scope which currently means that you're leaking memory because you have no pointer pointing at the data of the person_t
object of the previous loop cycle. 在堆上创建一个
person_t
对象,并用数据填充它,因为person_t
对象在堆上分配的new_person
超过了循环范围,这当前意味着您正在泄漏内存,因为您没有指针指向该对象的person_t
对象的数据上一个循环周期。
Both ways are correct !! 两种方法都是正确的!
person_t *new_person = (person_t *) malloc(sizeof(person_t));
and then change get_person_info() to accept a person_t ** instead of a person_t *?然后更改get_person_info()以接受person_t **而不是person_t *?
you don't need to change parameter of function - void get_person_infperson_t *person);
您不需要更改函数的参数
void get_person_infperson_t *person);
.Just pass pointer to it in main
like this - 只需像这样在
main
传递指向它的指针-
get_person_info(new_person);
But in previous way without allocating memory , you won't be able to use it outside the block it is defined in whereas if your program depend on its life you can allocate memory to it on heap. 但是以以前的方式,如果不分配内存,您将无法在定义它的块之外使用它,而如果您的程序依赖于它的生命,则可以在堆上分配内存。
In your code you posted new_person
is used inside loop
only so if you don't intend to use to outside loop you probably won't need dynamic allocation . 在您的代码中,您发布的
new_person
仅在内部loop
使用,因此,如果您不打算在外部循环中使用,则可能不需要动态分配 。
But if you want to use it outside loop
also you should use dynamic allocation. 但是,如果要在
loop
外使用它,则还应该使用动态分配。 But don't forget to free
it. 但是不要忘记
free
它。
Not sure whether or not to
malloc
memory for a struct?不知道是否要
malloc
内存,一个结构?
The short answer is: no need to do it in your case . 简短的答案是: 无需根据您的情况进行操作 。 If you want to use your object outside the
for
loop you could do it by dynamically allocated memory, namely: 如果要在
for
循环外使用对象for
可以通过动态分配的内存来实现,即:
person_t *new_person = malloc(sizeof(person_t));
and then call it with: 然后调用:
get_person_info(new_person);
In you example, the object is used within the loop, thus there is no need to do it. 在您的示例中,该对象在循环内使用,因此无需这样做。
when you use dynamically allocated memory you should always free it, at the end to avoid memory leaks. 使用动态分配的内存时,应始终释放它,最后避免内存泄漏。
As pointed out by @Johann Gerell, after removing the redundancy of the casting of the return type of malloc, in C, the allocation would look like: 正如@Johann Gerell指出的那样,在C语言中删除malloc返回类型的强制类型转换的冗余之后,分配看起来像:
person_t *new_person = malloc(sizeof(person_t));
malloc
returns a void pointer (void *
), which indicates that it is a pointer to a region of unknown data type.malloc
返回一个void指针(void *
),这表明它是指向未知数据类型区域的指针。 The use of casting is required in C++ due to the strong type system, whereas this is not the case in C.由于强类型系统,在C ++中需要使用强制转换,而在C中则不是这种情况。
Your confusion stems from not understanding object storage duration and pointers well. 您的困惑源于对对象存储持续时间和指针的理解不深。 Let's see each one separately to get some clarity.
让我们分别查看每个对象,以使内容更清晰。
An object can have automatic or dynamic storage duration. 一个对象可以具有自动或动态存储持续时间。
Automatic, as the name says, would be managed by the compiler for you. 顾名思义,自动将由编译器为您管理。 You just define a variable, use it and when it goes out of scope the object is destroyed automatically for you.
您只需定义一个变量,使用它,当它超出范围时,该对象将自动为您销毁。 A simple example:
一个简单的例子:
if (flag) {
int i = 0;
/* some calc. involving i */
}
// i is dead here; it cannot be accessed and its storage is reclaimed
When the control enters the if
's scope, memory large enough to hold an int
will be allocated automatically and assigned the value 0
. 当控件进入
if
的范围时,将自动分配足够容纳int
内存,并为其分配值0
。 Once your use of i
is over, when the control exits the scope, the name i
goes out of scope and thus will no longer be accessible by the program and also its storage area allocated automatically for you would be reclaimed. 一旦您对
i
的使用结束,则当控件退出范围时,名称i
将超出范围,因此程序将不再可访问它,并且将自动回收为其自动分配的存储区。
Lets say you want to have objects dynamically allocated ie you want to manage the storage and thereby the lifetime of the object without the scope or the compiler coming in your way, then you'd go on by requesting storage space from the platform using malloc
假设您要动态分配对象,即要管理存储,从而在不影响范围或编译器的情况下管理对象的生存期,然后继续使用
malloc
向平台请求存储空间
malloc(sizeof(int));
Notice that we're not assigning the return value of malloc
to any pointer as you're used to seeing. 请注意,正如您经常看到的那样,我们没有将
malloc
的返回值分配给任何指针。 We'll get to pointers in a bit, lets finish dynamic objects now. 我们将稍等一下指针,让我们现在完成动态对象。 Here, space large enough to hold an
int
is handed over to you by malloc
. 在这里,
malloc
将足够大的空间容纳一个int
。 It's up to you to free
it when you're done with it. 完成操作后,您可以自行
free
它。 Thus the lifetime of this unnamed int
object is in your hands and would live beyond the scope of the code that created it. 因此,这个未命名的
int
对象的生命周期掌握在您的手中,并且超出了创建它的代码范围。 It would end only when you explicitly call free
. 仅当您显式调用
free
时,它才会结束。 Without a matching free
call getting called, you'd have the infamous memory leak . 如果没有匹配的
free
电话被调用,您将臭名昭著的内存泄漏 。
A pointer is just what its name says - an object that can refer to another object. 指针就是它的名字所说的-一个可以引用另一个对象的对象。 A pointer is never what it is pointing at ( pointee ).
指针永远不会指向( pointee )。 A pointer is an object and its pointee is another separate, independent object.
指针是一个对象,其指针是另一个单独的独立对象。 You may make a pointer point to another named object, unnamed object, or nothing (
NULL
). 您可以使一个指针指向另一个命名对象,未命名对象或不指向任何对象(
NULL
)。
int i = 0;
int *ptr1 = &i; // ptr1 points to the automatic int object i
int *ptr2 = malloc(sizeof(int)); // ptr2 points to some unnamed int object
int *ptr3 = NULL; // ptr3 points to nothing
Thus the reason most people confuse pointers for dynamically allocated pointees comes from this: the pointee, here, doesn't have a name and hence they're referred to always via their pointers; 因此,大多数人将指针混淆为动态分配的指针的原因来自此:指针在这里没有名称,因此始终通过指针来引用它们。 some people mistake one for the other.
有些人将一个人误认为另一个人。
The function taking a pointer is appropriate here, since from the caller's viewpoint it's a flexible function: it can take both automatic and dynamic objects. 带有指针的函数在这里是合适的,因为从调用者的角度来看,它是一个灵活的函数:它可以同时包含自动对象和动态对象。 I can create an automatic variable and pass it in, or I can pass a dynamic variable too:
我可以创建一个自动变量并将其传递,也可以传递一个动态变量:
void get_person_info(person_t *person);
person_t o { };
get_person_info(&a);
person_t *p = malloc(sizeof(person_t));
get_person_info(p);
free(p);
Is it necessary to
malloc()
memory fornew_person within main()
?是否有必要
new_person within main()
为new_person within main()
malloc()
内存?
No. You can define an automatic variable and pass it to the function. 不可以。您可以定义一个自动变量并将其传递给函数。 In fact it's recommended that you try to minimize your usage of dynamic objects and prefer automatic objects since
实际上,建议您尽量减少对动态对象的使用,而首选自动对象,因为
free
to a malloc
thereby introducing a memory leak. malloc
free
调用匹配,从而导致内存泄漏。 However, automatic variables are generally allocated in the stack and thus the upper limit on the number and size on how much you can create on the stack is relatively lower than what you can allocate dynamically (generally from the heap). 但是,自动变量通常在堆栈中分配,因此,在堆栈上可以创建的数量和数量的上限相对于可以动态分配(通常是从堆中分配)的数量相对较低。
change
get_person_info()
to accept aperson_t **
instead of aperson_t *
?更改
get_person_info()
以接受person_t **
而不是person_t *
吗?
No, if you did so, the option of passing automatic variables would still be possible but cumbersome: 不,如果您这样做的话,传递自动变量的选项仍然可能,但是很麻烦:
void foo(int **o);
int i = 0;
int *p = &i; // p is redundant
foo(&p);
int *p = malloc(sizeof(int));
foo(&p);
As opposed the simpler 相对更简单
void bar(int *o);
int i = 0;
bar(&i);
int *p = malloc(sizeof(int));
bar(p);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.