【问题标题】:single malloc for creating 2 structs用于创建 2 个结构的单个 malloc
【发布时间】:2014-03-14 09:32:51
【问题描述】:

我有一个具有这种结构的节点:

struct node
{
    unsigned long key;
    unsigned long value;
    struct node* lChild;    
    struct node* rChild;   
};

我有一个具有默认值的虚拟节点:

struct node* newSpecialNode()
{
    struct node* node = (struct node*) malloc(sizeof(struct node));
    node->key = 0;
    node->value = 0;
    node->lChild = NULL;
    node->rChild = NULL;
    return(node);
}

我的数据结构中的所有节点都会调用这个方法来创建一个节点。

struct node* newInternalNode(unsigned long key, unsigned long value)
{
    struct node* node = (struct node*) malloc(sizeof(struct node));
    node->key = key;
    node->value = value;
    node->lChild = newSpecialNode();
    node->rChild = newSpecialNode();
    return(node);
}

我为左右孩子调用函数newSpecialNode()。 所以有两个malloc 调用。但是每当我创建一个节点时,我总是会创建两个虚拟节点。 所以我想做一个为lChildrChild 分配内存的malloc。 可能分配一个双字并引用它的部分。但我不知道该怎么做。

我尝试了这种方法。但是我又需要做两个 malloc。

struct node** ptrToTwoNodes = (struct node**) malloc(2*sizeof(struct node*));
ptrToTwoNodes[0] = (struct node*) malloc(sizeof(struct node));
ptrToTwoNodes[1] = (struct node*) malloc(sizeof(struct node));

【问题讨论】:

  • struct node* ptrToTwoNodes = (struct node*) malloc(2*sizeof(struct node));, (ptrToTwoNodes), (ptrToTwoNodes+1)
  • 要考虑的重要一点是,如果您在单个 malloc() 调用中分配多个节点,则需要将这些节点作为一个块释放。这可能意味着您必须跟踪哪个指针是要被释放的指针,并且只有在 all 指向它的指针不再使用时才释放该块。如果您需要能够独立释放 lChildrChild(或以其他方式将所有权转移给可能持有指向 node 的指针的其他事物),您应该坚持使用单独的 malloc() 调用。

标签: c memory-management malloc


【解决方案1】:

虽然从技术上讲,您可以使用单个 malloc() 分配所有三个节点,但您确实不应该这样做,因为它破坏了树结构的递归“对称性”。

当调用malloc() 三次时,你会得到一棵树,其中每个节点都是相互独立的。这意味着您可以在以后更改树(添加和删除节点),而不必担心子节点是如何分配的。

问题的根源在于您不能将内存段的free() 部分返回我的malloc()。对于malloc() 返回的每个指针,您总是必须只调用一次free() - 不多也不少。

如果 malloc 对您来说过于昂贵,那么另一种方法是创建一组辅助函数来保存节点结构池(因此它们一次分配 N,然后一个接一个地返回,直到池用完)。见object pool pattern

【讨论】:

  • 很好的解释!!谢谢.. 我尝试做一个 malloc 的 3 个原因。 1.我没有做任何GC。 2. 我在并发设置中使用它,还没有找到 GC 算法。 3.这些特殊节点永远不会改变值,它们只会被另一个内部节点替换
  • Re 3:如果“替换”对您来说意味着“更改 l/rChild 指针”,那么请记住,这会造成(小)内存泄漏。我目前的感觉是,您有一个如何解决问题的想法,但这个想法很糟糕。也许如果您告诉我们您要解决什么问题,我们可以为您提供更好的选择。
  • 比方说,我创建了两个 malloc(每个孩子一个)。当我“替换”一个节点(是的,我正在更改 l/r 子指针)时,我仍然无法释放这个被替换节点的内存。原因是其他线程仍然可以在并发设置中保持对它的引用。因此,在我为我的算法找到一个 GC 之前,我计划采用这种方法。
【解决方案2】:

如果你想为两个节点分配一块内存,试试

struct node* ptrToTwoNodes = (struct node*) malloc(2*sizeof(struct node));

那么&ptrToTwoNodes[0]&ptrToTwoNodes[1] 将是指向你的两个节点的指针。顺便说一句,我猜你应该删除 C++ 标签。

【讨论】:

  • 谢谢。有效。这个想法很简单,并没有让我印象深刻:)有人为我删除了C++标签
【解决方案3】:

您可以为2个节点分配内存,并将指针分配给一个变量:

struct node* ptrToTwoNodes = (struct node*) malloc(2*sizeof(struct node));
ptrToTwoNodes[0].value = ...;
ptrToTwoNodes[1].value = ...;

【讨论】:

    【解决方案4】:

    我不确定你的最终结果是什么,但你可以这样做:

    struct node
    {
        unsigned long key;
        unsigned long value;
        struct node* Child;    //allocate two 2 node sized blocks for it & access left-Child[0], right-Child[1]
    };
    

    并初始化为:

    struct node* newSpecialNode()
    {
        struct node* node = (struct node*) malloc(sizeof(struct node));
        node->key = 0;
        node->value = 0;
        node->Child = NULL;
        return(node);
    }
    

    然后像这样分配:

    struct node* newInternalNode(unsigned long key, unsigned long value)
    {
        struct node* node = (struct node*) malloc(sizeof(struct node));
        node->key = key;
        node->value = value;
        node->Child = malloc(sizeof(sruct node)*2); //Child[0] & Child[1] 
        return(node);
    }
    

    【讨论】:

      【解决方案5】:

      修改代码如下:

      struct node * newSpecialNode(void)
      {
        struct node * node = malloc(2 * sizeof(*node));
        node->key = 0;
        node->value = 0;
        node->lChild = NULL;
        node->rChild = NULL;
        ++node;
      
        node->key = 0;
        node->value = 0;
        node->lChild = NULL;
        node->rChild = NULL;
        --node;
      
        return node;
      }
      
      struct node * newInternalNode(unsigned long key, unsigned long value)
      {
        struct node * node = malloc(sizeof(*node));
        node->key = key;
        node->value = value;
        node->lChild = newSpecialNode();
        node->rChild = node->lChild + 1; 
      
        return node;
      }
      

      注意如何free() 事情。

      还为所有malloc()s 添加错误检查。

      还有^2:In C there is no need to cast the result of malloc(), nor is it recommended.

      【讨论】:

      • 你的意思是我可以安全地将struct node * node = (struct node*) malloc(2 * sizeof(*node)); 替换为struct node * node = malloc(2 * sizeof(*node)); 吗?
      • @arunmoezhi:在 C 中你应该,是的。
      • 去除类型转换会提高性能吗?实际上我不会看到任何显着的变化。但理论上它会减少汇编指令的数量吗?
      • 这将使您的代码更安全,因为演员可能很容易隐藏错误......仅此而已。
      猜你喜欢
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 2011-03-07
      • 2015-02-12
      • 1970-01-01
      相关资源
      最近更新 更多