不确定是否为结构的malloc内存

时间:2015-09-11 10:40:17

标签: c pointers segmentation-fault malloc dynamic-memory-allocation

假设我有以下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;
}

其中get_person_info()只填写传入指针的person_t结构。malloc()new_person的{​​{1}}内存是否必要?也就是说,该行

main()

而不是

person_t new_person;

然后更改person_t *new_person = (person_t *) malloc(sizeof(person_t)); 接受get_person_info()而不是person_t **

很抱歉,如果这个问题令人困惑 - 我不确定这是否是需要保留内存的情况,因为指向该内存的指针被传递到person_t *以避免导致分段错误。

4 个答案:

答案 0 :(得分:2)

两者都是正确的,这取决于您要使用person_info的位置。 在堆栈上分配:

 for (int i = 0; i < NUM_PEOPLE; i++) {
        person_t new_person;
        get_person_info(&new_person);
    }

在堆栈上创建一个person_t对象并使用数据填充new_person对象,因为循环只会这样做,对象在下一次循环迭代时超出范围并且数据丢失。

使用malloc:

for (int i = 0; i < NUM_PEOPLE; i++) {
        person_t *new_person = malloc(sizeof(person_t));
        get_person_info(new_person);
    }

在堆上创建一个person_t对象并用数据填充它,因为它在堆上分配的new_person对象将比循环范围更长,这当前意味着你正在泄漏内存,因为你有没有指针指向前一个循环周期的person_t对象的数据。

答案 1 :(得分:1)

两种方式都是正确的!

  

void get_person_infperson_t *person);   然后更改get_person_info()以接受person_t **而不是person_t *?

您无需更改功能参数 - main。只需将指针传递给get_person_info(new_person); ,就像这样 -

new_person

但是在以前没有分配内存的情况下,你将无法在定义的块之外使用它,而如果你的程序依赖于它的生命,你可以在堆上为它分配内存。

在您的代码中,loop仅在loop内使用,因此如果您不打算使用外部循环,则可能不需要动态分配

但是如果你想在free之外使用它,你也应该使用动态分配。但不要忘记public static event DownEventHandler Down; public static delegate void DownEventHandler(string Key); Down(FunctionChar((Keys)lParam.Code)); // lParam.code is an integer value. private string FunctionChar(Keys e) { if(e >=65 && e<=90){ if (Control.IsKeyLocked(Keys.CapsLock) || ((Control.ModifierKeys !=0) && (Keys.Shift) != 0)) { return e.ToString; } else { return e.ToString.ToLower; } 它。

答案 2 :(得分:1)

  

不确定结构的malloc内存是否存在?

简短的回答是:无需在您的情况下执行。如果你想在for循环之外使用你的对象,你可以通过动态分配的内存来实现它,即:

person_t *new_person = malloc(sizeof(person_t));

然后用:

调用它
 get_person_info(new_person);

在您的示例中,对象在循环中使用,因此无需执行此操作。

注意:

当你使用动态分配的内存时,你应该总是释放它,最后避免内存泄漏。

编辑:

正如@Johann Gerell所指出的,在删除了返回类型malloc的转换的冗余之后,在C中,分配看起来像:

person_t *new_person = malloc(sizeof(person_t));
  

malloc返回一个void指针(void *),表示它是指向未知数据类型区域的指针。由于强类型系统,在C ++中需要使用强制转换,而在C中则不是这样。

答案 3 :(得分:1)

您的困惑源于不了解对象存储持续时间和指针。让我们分别看一下,以便清楚一点。

存储持续时间

对象可以具有自动或动态存储持续时间。

自动

自动,顾名思义,将由编译器为您管理。您只需定义一个变量,使用它,当它超出范围时,对象会自动为您销毁。一个简单的例子:

if (flag) {
    int i = 0;
    /* some calc. involving i */
}
// i is dead here; it cannot be accessed and its storage is reclaimed

当控件进入if的范围时,将自动分配足以容纳int的内存,并为其分配值0。一旦您使用i结束,当控件退出作用域时,名称i超出范围,因此程序将无法再访问它,并且它将自动为您分配存储区域被收回。

动态

让我们假设您想要动态分配对象,即您希望管理存储,从而管理对象的生命周期,而不会使用作​​用域或编译器,然后您将继续从平台请求存储空间使用malloc

malloc(sizeof(int));

请注意,我们并未将malloc的返回值分配给您以前看到的任何指针。我们将稍微指出一下,让我们现在完成动态对象。在此,int会将大到足以容纳malloc的空间移交给您。当你完成它时,由free来决定你。因此,这个未命名的int对象的生命周期在你手中,并且超出了创建它的代码的范围。只有在您明确调用free时才会结束。如果没有匹配的free来电,您就会有臭名昭着的memory leak

指针

指针就是它的名字所说的 - 一个可以引用另一个对象的对象。指针永远不会指向它( pointee )。指针是一个对象,它的指针是另一个独立的独立对象。您可以将指针指向另一个命名对象,未命名对象或任何内容(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

因此,大多数人混淆动态分配的指针的指针的原因来自于:指针,这里没有名称,因此它们总是通过指针引用;有些人误认为是另一个。

功能接口

这里采用指针的功能是合适的,因为从调用者的角度来看,它是一个灵活的功能:它可以同时采用自动和动态对象。我可以创建一个自动变量并将其传入,或者我也可以传递一个动态变量:

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);
  

malloc()是否需要new_person within main()内存?

没有。您可以定义自动变量并将其传递给函数。实际上,建议您尝试最小化动态对象的使用并优先选择自动对象

  • 它可以最大限度地减少代码中内存泄漏的可能性。即使是经验丰富的程序员也会错过调用匹配的freemalloc,从而导致内存泄漏。
  • 动态对象分配/释放比自动变量分配/释放慢得多。
  • 许多动态分配解除分配会导致内存碎片化。

但是,自动变量通常在堆栈中分配,因此可以在堆栈上创建的数量和大小的上限相对低于动态分配的值(通常来自堆)。

  

更改get_person_info()接受person_t **而不是person_t *

不,如果你这样做,那么传递自动变量的选项仍然是可能的,但是很麻烦:

void foo(int **o);

int i = 0;
int *p = &i;  // p is redundant
foo(&p);

int *p = malloc(sizeof(int));
foo(&p);

与简单的

相反
void bar(int *o);

int i = 0;
bar(&i);

int *p = malloc(sizeof(int));
bar(p);