【问题标题】:Why do I have to use malloc when I have a pointer to a struct?当我有一个指向结构的指针时,为什么我必须使用 malloc?
【发布时间】:2013-12-26 01:16:16
【问题描述】:
 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);

【问题讨论】:

  • 因为指针不是“事物”,只是指向它的指针。你必须以某种方式分配“东西”。
  • 另外,我不知道“z = 6”应该做什么。这甚至可以编译吗?
  • 你泄露了你 malloc 的第一个 ELEM。
  • 事实上,这些东西有用吗???
  • [插入关于不强制转换 malloc 结果的强制性评论]

标签: c pointers struct


【解决方案1】:

声明一个指针只会创建一个指针。必须有一些东西可以指向这就是malloc 给你的。

或者,您可以在堆栈上创建结构(也称为“自动存储”):

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

【讨论】:

    【解决方案2】:

    指针只是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
    

    【讨论】:

      【解决方案3】:

      在你的第一个例子中,

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

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

      ELEM *z;
      

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

      【讨论】:

        【解决方案4】:

        如果你打算动态分配内存,你只需要使用malloc。否则,您的指针必须指向 something。如果您打算在指针未指向有效内存时使用它,这是未定义的行为。

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

        【讨论】:

          【解决方案5】:

          让我们尝试使用您的 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);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-04-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-30
            • 1970-01-01
            • 2022-01-02
            • 1970-01-01
            相关资源
            最近更新 更多