【问题标题】:Memory Management C and free() of pointers内存管理 C 和指针的 free()
【发布时间】:2017-04-21 16:44:22
【问题描述】:

所以我对如何进行正确的内存管理有一些疑问。

基本上我的问题是,例如,当我使用此代码时会发生什么(如下所示)。是否需要释放它以防止内存泄漏?

    void traverseLeftRight(struct node *head){

        current = head;

        if(current == NULL){

            printf("There are no nodes within the list\n");
        }

        while(1){

            if(current != NULL){

                printf("left to right output:           %d\n", current -> value);
                current = current -> next;
            }else{

                break;
            }
        }
    }

此外,如果我在列表的中断部分执行此操作,那么 free(current) 和 current = NULL 是否会中断该列表。另外,这样的事情会破坏指向变量而不影响它对应的节点吗?

void traverseLeftRight(struct node *head){

    current = head;

    if(current == NULL){

        printf("There are no nodes within the list\n");
    }

    while(1){

        if(current != NULL){

            printf("left to right output:           %d\n", current -> value);
            current = current -> next;
        }else{

            free(current);
            current = NULL;
            break;
        }
    }
}

【问题讨论】:

  • 每个分配都应该与一个空闲空间配对,在不再需要分配的空间后执行。仅仅访问分配的内存不会产生任何额外的义务。
  • 至于您提议的代码变体,这绝对没有意义。仅当 current 已计算为 NULL 时,才输入 else 块。释放它或将其冗余设置为 NULL 没有用。
  • 好的,谢谢,当我使用类似 current 的东西时,我最初想到的是我需要释放我用于它的值。感谢您澄清这一点。
  • 所以为了清楚起见,我只会在我当前从我正在使用的列表中删除一个节点时释放,因为这是需要分配或在程序结束时?那么除非由 c 库函数(一般而言)指定,否则没有其他地方?
  • 是的,当您从列表中删除一个动态分配的节点时,自然会释放它的内存,并且在任何情况下都不能在它保持 in 时释放它的内存i> 列表。细节需要参考具体代码。

标签: c pointers memory-management


【解决方案1】:

我认为您对内存管理感到困惑。

在您展示的示例中,不需要任何释放,因为(据我们所见)没有分配任何内容。

如果您使用 malloc(3) 或朋友分配内存,那么您通常需要稍后释放它,只需要一次。一般来说,未能释放某些东西会泄漏内存(即,内存仍然被分配,但你不再指向它,所以不能使用它),并且多次释放是一个错误(在某种意义上这开启了代码的两位都认为它们已被分配独占使用同一位内存的可能性)。在释放后使用一点内存(即取消引用指针)是典型的“释放后使用”错误。这些中的每一个都会导致一些难以发现的错误(但valgrind 是你的朋友)。

第二次调用free(很遗憾)不会导致错误,因为free 不会报告此类错误。

如果内存一直使用到程序结束,则无需释放内存 - (实际上)程序结束时会自动释放。

几乎唯一在这样的函数中调用free 的情况是,如果你正在编写一个函数来沿着链表(或类似的东西)走动,并在它走的时候释放它。列表的遍历(正如您的函数名称所暗示的那样)不会导致列表被释放。

【讨论】:

  • 好吧,我想我没听说过“走路”这个词。你这是什么意思?
  • 啊,对不起。沿着列表走是您在该功能中所做的事情:从一个链表项目到另一个链表项目,current = current->next(也许想想垫脚石)。
  • 第二个代码中没有与调用free()相关的错误。将空指针传递给free() 并没有错;这样做很明确,不会产生任何影响。
  • @JeffreyHennen 是的,这通常是正确的,但在这种情况下,您在 current已经 null 的分支中执行 free - 也就是说,在没有什么可以释放的分支中。你的意思是free 在另一个分支吗?这是假设这个函数的目的是遍历链表,边走边释放。也许您需要在此函数顶部添加一个“此函数将...”目的注释...!
  • @JeffreyHennen 啊哈!我们可能已经找到了您困惑的根源。当您使用malloc 分配内存时,系统会保留一块RAM 供您使用,并为您提供指向它的指针(例如,struct node* my_ptr)。您可以传递该指针,包括将其分配给其他struct node*,或将其传递给函数,但是当您完成它时,可能要很久以后,您必须告诉系统您不再需要它(与free)。但是您释放的是 memory,而不是指向它的 pointerVariables within a function 不同。
【解决方案2】:

这是您的第一个代码,已更正,因此空列表不会进入“while()”循环

void traverseLeftRight(struct node *head)
{

    current = head;

    if(current == NULL)
    { // then list empty
        printf("There are no nodes within the list\n");
    }

    while( current != NULL )
    { // then, another node to print
        printf("left to right output:           %d\n", current -> value);
        current = current->next;   // step to next node in list
    }
}

这是您的第二个代码,带有 cmets

while(1)
{

    if(current != NULL)
    { // then, not at end of list
        printf("left to right output:           %d\n", current -> value);
        current = current->next;  // step to next entry in list
    }

    else
    { // else, current == NULL ,, I.E. past end of list

        free(current);    // nothing will happen because Current == NULL
        current = NULL;   // already NULL, so nothing will change
        break;            // exit the 'while()' loop
    }
}

在遍历链表时释放链表的建议代码。

请注意,“head”需要更新,因为列表是“free”的

// note the 'pointer to pointer parameter, so 'head' can be modified
void traverseLeftRight(struct node **head)  
{
    if( *head == NULL)
    {  // then, list is empty
        printf("There are no nodes within the list\n");
    }

    while( *head != NULL)
    { // while another node to process
        struct node *temp = *head; // remember current node pointer
        printf("left to right output:           %d\n", current -> value);
        *head = (*head)->next;     // step to next node
        free( temp );              // eliminate current node
    }
}

【讨论】:

  • 好吧,关于遍历的代码。我在这里没有提到它,但是这些函数集中的每一个都与标题一起使用,所以我没有在这些函数中初始化 current(我只使用 current,因为它更容易理解)。
  • 另外,这段代码并不是真正释放代码,这只是为列表中的每个节点赋予相应的值。我有一个不同的功能,它不是这样做的一部分。
  • 不应在头文件中声明变量。 (虽然数据类型可以在头文件中定义。)
  • @JeffreyHennen,发布的代码在节点上调用free(),所以我建议的答案在节点上调用free()。请提出问题,以免造成此类误解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多