当我有一个指向结构的指针时,为什么我必须使用malloc?

时间:2013-12-26 01:16:17

标签: c pointers struct

 struct element {
     int val;
     int z;
 };
 typedef struct element ELEM;

看看这个例子:

 int main()
 {

    ELEM z;
    z =  6;
    printf("%d",z);
 }

一切正常,但如果我有一个指向结构的指针,我需要编写如下代码:

ELEM *z;
p = (ELEM*)malloc(sizeof(ELEM)); // Without this will not work
(*p).val = 3;
p = (ELEM*)malloc(sizeof(ELEM));
printf("%d",(*p).val);

5 个答案:

答案 0 :(得分:7)

声明指针不会创建除指针之外的任何内容。必须有一些东西可以指向这是malloc给你的东西。

或者,您可以在堆栈上创建结构(a.k.a。“自动存储”):

ELEM z;
ELEM *p = &z;
(*p).val = 3; // Also could be written as p->val = 3;
printf("%d",(*p).val);
顺便说一下,你的指针代码有一个错误,因为它泄漏了(即丢失了)第一个分配的结构:

ELEM *p;
p = (ELEM*)malloc(sizeof(ELEM));
(*p).val = 3;
p = (ELEM*)malloc(sizeof(ELEM)); // <- leak here: pointer to old struct lost.
printf("%d",(*p).val);

删除第二个malloc可解决问题。一个完整的,已修复的版本,看起来更像您在使用中看到的代码:

ELEM *p = (ELEM*)malloc(sizeof(ELEM));
p->val = 3;
printf("%d\n", p->val);
free(p);

每个malloc应该有free,除非您的程序通过终止释放内存。即便如此,拥有free

也很不错

答案 1 :(得分:4)

指针只是C / C ++中对象的地址,而不是对象本身。在32位系统中,其长度始终为4个字节。当您创建指针时,如果您没有初始化它或为其分配内存,它将引用无效的地址。因此,您必须通过调用malloc动态创建对象(在C ++中,您可以使用new关键字),然后它可以引用所创建对象的地址。

ELEM elem; //This will create the object at stack.
ELEM* pElem; //This just create an invalid poiter which point to unknown address
pElem = &elem; //This initialize the pointer which point to the address if "elem" above
pElem = (ELEM*)malloc(sizeof(ELEM)); //This create a new memory which contain the object "ELEM" and pElem will point to the address of the object

答案 2 :(得分:1)

在你的第一个例子中,

int main() {
  ELEM z;
  z =  6;
  printf("%d",z);
}

您正在堆栈上创建z Elem。这是一个非常有效的操作,语言将为您管理分配给z的内存 - 即z超出范围时,它将自动被释放。相比之下,你的第二个例子,

ELEM *z;

在堆栈上创建一个指针(在32位操作系统上为32位值,在64位操作系统上为64位值),但不分配任何元素。这就是malloc例程的目的,即在堆上分配内存。您可以通过指向堆的指针动态地指向一个(如在您的示例中)或许多不同的元素,并且您必须释放您分配的内存。

答案 3 :(得分:0)

如果您打算动态分配内存,则只需使用malloc。否则,您的指针必须指向某事。如果您打算在没有指向有效内存的情况下使用指针,则它是未定义的行为。

struct Elem
{
    int val;
};

int main() {
    struct Elem elem;
    struct Elem* ptr; // can't use pointer, points to nothing
    ptr = &elem; // good, points to elem
    ptr->val = 5;
    printf("%d", ptr->val);
    ptr = malloc(sizeof(struct Elem)); // good, points to object on the heap
    ptr->val = 10;
    printf("%d", ptr->val);
    free(ptr);
    return 0;
}

答案 4 :(得分:0)

让我们尝试使用您的struct定义对其进行可视化。

struct element
{
     int val;
     int z;
};
typedef struct element ELEM;

当你声明一个这种类型的变量时,它会在内存中安全地分配,也就是说,当它在范围内时,实现不会将此内存用于其他任何内容。

ELEM e;

   val     z  
e[ int ][ int ]

当声明指向此类型变量的指针并且不初始化它时,它指向某个未定义的位置。

ELEM *pE;

    val      z
pE[ int  ][ int ]

该指针即使已经初始化,仍然认为自己指向ELEM。它所指向的实际地址可能是“无害的”,也就是说,您实际上可以使用它而不会导致任何运行时问题。但是,如果您很幸运,如果您使用它,您将收到运行时错误,例如分段错误。发生这种情况是因为您访问了非法的内存位置。如果你正在写作,你可以写代码或数据并破坏它。

pE必须指向一个安全的内存位置,一个已为ELEM分配的位置:

pE = &e;

         val     e
pE -> e[ int ][ int ]

pE现在指向e。它可以安全地从这个内存位置读写,没有任何危险。

您还可以使用malloc:

pE个人分配内存
pE = malloc(sizeof(*pE);