【问题标题】:Correctly freeing pointer to linked list正确释放指向链表的指针
【发布时间】:2013-11-19 19:40:29
【问题描述】:

在使用垃圾收集语言 10 多年后,我回到了 C99,显然我在内存管理方面遇到了困难。

我有一个由堆栈项和类型Stack 组成的链表,该类型指向该链表第一个元素的地址。

这是我目前的代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct StackItem
{
    int head;
    struct StackItem* next;
} StackItem;

typedef StackItem** Stack;

StackItem* makeStackItem (int head)
{
    StackItem* a = (StackItem*) malloc (sizeof (StackItem) );
    a->head = head;
    a->next = (StackItem*) 0;
    return a;
}

Stack makeStack ()
{
    Stack stack = (Stack) malloc (sizeof (StackItem*) );
    *stack = (StackItem*) 0;
    return stack;
}

void pushStack (StackItem* item, Stack stack)
{
    item->next = *stack;
    *stack = item;
}

void freeStack (Stack stack)
{
    StackItem* current = *stack;
    StackItem* next;
    while (current != 0)
    {
        next = current->next;
        free (current);
        current = next;
    }
    free (stack);
}

int main ()
{
    Stack stack = makeStack ();
    for (int i = 0; i < 10; i++)
        pushStack (makeStackItem (i), stack);
    printf ("Here be dragons.\n");
    freeStack (stack);
    return 0;
}

我的问题是:

  1. makeStackmakeStackItem 的第一行是否合理且 有必要吗?

  2. freeStack的最后一行是否合理必要?

  3. 一旦main 返回,我之前是否释放了所有内存 分配了吗?

  4. 如何查看我是否有内存泄漏?

非常感谢您。

【问题讨论】:

  • 关于您的第四个问题,我建议您查看valgrind
  • 不鼓励使用 malloc。我个人讨厌在 typedef 中隐藏间接寻址,这会降低代码的可读性( typedef StackItem** Stack; )
  • 查理打败了我,但这就是为什么 - stackoverflow.com/questions/605845/…
  • 在类型声明中,星号绑定到右边,并且应该间隔以强调这一点:StackItem *stacknot StackItem* stack。 (很多人说正好相反。他们错了。)
  • 谢谢大家。我会调查这个 valgrind。

标签: c malloc c99


【解决方案1】:

makeStack 和 makeStackItem 的第一行是否合理且必要? yes except for the casting malloc issue

freeStack 的最后一行是否合理且必要? yes

一旦 main 返回,我是否释放了之前分配的所有内存? yes

如何查看我是否有内存泄漏? use valgrind

I would toss the casts of 0 too.

【讨论】:

  • 只是为了让您正确:基本上将(sometype*) malloc ()替换为malloc (),将(sometype*) 0替换为0?
  • 是的,这就是我的建议。
  • (sometype*)0 在您将空指针作为匿名参数之一传递给可变参数或非原型函数时(并且 时)是必需的。在那种单独的上下文中,一个裸露的0 不会在您需要时转换为空指针。您可能遇到此问题的唯一一次是execl 系列,其最后一个参数必须始终为(char *)0。另请注意,使用NULL 不会让您无需在此上下文中进行显式转换,因为#define NULL 0&lt;stddef.h&gt; 做的合法事情。
  • @Zack 是因为 sizeof(int) != sizeof(int *) ?
  • 是的,还有其他更奇特的可能性,例如 CPU 区分“地址”和“数据”寄存器以及 ABI 需要将指针参数放入前者(最著名的是 M68K;仍然是在现代生活的可能性),或者空指针的位模式不是全为零(现在不太可能出现;模糊的记忆,一些 Burroughs minis 这样做了,不确定)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多