【问题标题】:What are some useful examples of malloc() in C?C 中有哪些有用的 malloc() 示例?
【发布时间】:2011-05-04 08:27:33
【问题描述】:

我正在阅读 C 语言中的 malloc()

Wikipedia article 提供了一个example,但与int array[10] 相比,它只是为10 个整数的数组分配了足够的内存。不是很有用。

您什么时候决定使用 malloc() 而不是 C 来为您处理内存?

【问题讨论】:

    标签: c malloc


    【解决方案1】:

    在您描述的示例中,int array[10] 在您离开堆栈帧时消失。如果您希望使用的内存超出本地范围,则必须使用 malloc();

    【讨论】:

      【解决方案2】:

      malloc() 在任何时候使用:

      1. 您需要动态内存分配
        如果您需要创建大小为 n 的数组,其中 n 是在程序执行期间计算的,那么唯一的方法就是使用 malloc()。

      2. 需要在堆中分配内存
        在某些函数中定义的变量只存在于该函数的末尾。因此,如果需要一些“与调用堆栈无关”的数据,则必须将其作为函数参数传递/返回(这并不总是合适的),或者存储在堆中。在堆中存储数据的唯一方法是使用 malloc()。有可变大小的数组,但它们是在堆栈上分配的。

      【讨论】:

      • 那么什么时候需要动态内存分配呢?
      • 可变长度数组呢?
      【解决方案3】:

      如果您在编写程序时不知道数组的大小怎么办? 举个例子,我们可以想象你想要加载一张图片。起初你不知道它的大小,所以你必须从文件中读取大小,分配一个这个大小的缓冲区,然后读取那个缓冲区中的文件。显然你不能使用静态大小的数组。

      编辑:

      另外一点是:当你使用动态分配时,内存是在堆上分配的,而数组是在栈上分配的。当您在嵌入式设备上编程时,这一点非常重要,因为与堆相比,堆栈的大小可能有限。

      【讨论】:

      • C99 提供可变长度数组,允许您使用在运行时确定的大小创建数组。
      • @dreamlax: 是的,但在这种情况下你不能使用 realloc()
      【解决方案4】:

      尽管您可以从 C99 开始制作可变长度数组,但仍然没有像样的替代品来替代更动态的数据结构。一个经典的例子是链表。要获得任意大小,您可以使用malloc 分配每个 节点,这样您就可以插入和删除而无需大量内存复制,就像可变长度数组的情况一样。

      例如,使用简单链表的任意大小的堆栈:

      #include <stdio.h>
      #include <stdlib.h>
      
      typedef struct sNode {
          int payLoad;
          struct sNode *next;
      } tNode;
      
      void stkPush (tNode **stk, int val) {
          tNode *newNode = malloc (sizeof (tNode));
          if (newNode == NULL) return;
          newNode->payLoad = val;
          newNode->next = *stk;
          *stk = newNode;
      }
      
      int stkPop (tNode **stk) {
          tNode *oldNode;
          int val;
          if (*stk == NULL) return 0;
          oldNode = *stk;
          *stk = oldNode->next;
          val = oldNode->payLoad;
          free (oldNode);
          return val;
      }
      
      int main (void) {
          tNode *top = NULL;
          stkPush (&top, 42);
          printf ("%d\n", stkPop (&top));
          return 0;
      }
      

      现在,可能使用可变长度数组来做到这一点,但是,就像用 COBOL 编写操作系统一样,有更好的方法来做到这一点。

      【讨论】:

        【解决方案5】:

        动态数据结构(列表、树等)使用malloc 在堆上分配它们的节点。例如:

        /* A singly-linked list node, holding data and pointer to next node */
        struct slnode_t
        {
            struct slnode_t* next;
            int data;
        };
        
        typedef struct slnode_t slnode;
        
        /* Allocate a new node with the given data and next pointer */
        slnode* sl_new_node(int data, slnode* next)
        {
            slnode* node = malloc(sizeof *node);
            node->data = data;
            node->next = next;
            return node;
        }
        
        /* Insert the given data at the front of the list specified by a 
        ** pointer to the head node
        */
        void sl_insert_front(slnode** head, int data)
        {
            slnode* node = sl_new_node(data, *head);
            *head = node;
        }
        

        考虑如何使用sl_insert_front 将新数据添加到列表中。您需要创建一个节点来保存数据和指向列表中下一个节点的指针。你打算在哪里创建它?

        • 也许在堆栈上! - - 堆栈空间将分配到哪里?在哪个功能?函数退出时会发生什么?
        • 可能在静态内存中! - - 你必须提前知道你有多少列表节点,因为静态内存是在程序加载时预先分配的。
        • 在堆上? 是的 - 因为您拥有所有必需的灵活性。

        malloc 在 C 中用于在堆上分配东西——内存空间可以在运行时动态增长和缩小,其所有权完全在程序员的控制之下。还有很多这样有用的例子,但我在这里展示的是一个有代表性的例子。最终,在复杂的 C 程序中,您会发现程序的大部分数据都在堆上,可以通过指针访问。正确的程序总是知道哪个指针“拥有”数据,并会在不再需要时仔细清理分配的内存。

        【讨论】:

        • 谢谢,这正是我想要的。
        【解决方案6】:

        我建议您使用谷歌搜索Stack and Heap

        int* heapArray = (int*)malloc(10 * sizeof(int));
        int stackArray[10];
        

        两者在您访问数据的方式上非常相似。它们在幕后存储数据的方式非常不同。 heapArray 在堆上分配,并且仅在应用程序死亡或调用free(heapArray) 时才被释放。 stackArray 在堆栈上分配,并在堆栈展开时被释放。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-07-16
          • 2012-05-02
          • 2011-08-31
          • 1970-01-01
          • 2014-01-17
          • 2011-06-02
          • 1970-01-01
          相关资源
          最近更新 更多