为什么在C中要使用两个临时变量来释放链表?

huangapple go评论164阅读模式
英文:

Why free linked list with two temporary variables in c?

问题

这段代码是我通过CS50课程学到的,最后一部分代码是由讲师编写的,用于释放已使用的内存:

```c
ptr = list;
while (ptr != NULL)
{
    node *next = ptr->next;
    free(ptr);
    ptr = next;
}

我理解使用next作为临时指针的必要性,但为什么要使用"ptr"(原始指针到链表开头"list"的临时指针)来释放内存?是否有不直接使用"list"的理由?

while (list != NULL)
{
    node *next = list->next;
    free(list);
    list = next;
}

我尝试使用上述代码,似乎也能正常工作;是否有直接释放"list"存在任何问题的担忧?


<details>
<summary>英文:</summary>

I am going through the CS50 course, and this last part of code was written by the instructor to free the memory used :

ptr = list;
while (ptr != NULL)
{
node *next = ptr->next;
free(ptr);
ptr = next;
}

I understand the need to use next as a temporary pointer, but why is &quot;ptr&quot; (a temporary point for the original pointer to the start of the linked list &quot;list&quot; used to free the memory? Is there any reason for not using &quot;list&quot; directly?


while (list != NULL)
{
node *next = list->next;
free(list);
list = next;
}

I tried doing this instead, and it seems to work the same; are there any concerns about freeing list directly?


</details>


# 答案1
**得分**: 1

在[CS50x 2023 - 数据结构讲座][1]中的大约1:22:00(一小时二十二分钟)处,展示了以下代码。

临时变量`ptr`存在的原因是因为讲师首先使用它来打印列表的内容,同时不丢失根节点(`list`本身)。

```C
node *ptr = list;
while (ptr != NULL)
{   
    printf("%i\n", ptr->number);
    ptr = ptr->next;
}

在这个循环之后,ptr变为NULL

然后,ptr被重复使用(再次设置为list)来执行释放所有节点的循环,正如在你的第一个代码片段中所示。

这纯粹是一种风格选择 - 如果你不在意保留它持有的值(在free之后无用),你也可以只使用list。实际上,在前一年的讲座(CS50 2021 in HDR - Lecture 5 - Data Structures)中,使用了以下代码:

while (list != NULL)
{   
    node *tmp = list->next;
    free(list);
    list = tmp;
}

这个代码片段做的就是这样。

英文:

At around 1:22:00 (one hour and twenty-two minutes) in CS50x 2023 - Lecture 5 - Data Structures, this code is shown.

The temporary ptr exists simply because the lecturer uses it to first print the contents of the list, without losing track of the root node (list itself).

node *ptr = list;
while (ptr != NULL)
{   
    printf(&quot;%i\n&quot;, ptr-&gt;number);
    ptr = ptr-&gt;next;
}

After this loop, ptr is NULL.

ptr is then reused (again set to list beforehand) for the loop that frees all the nodes, as seen in your first snippet.

This is purely a style choice - you could just as well use just list if you do not care to retain the value it holds (useless after free). In fact, in a previous year's lecture (~ 1:07:00 in CS50 2021 in HDR - Lecture 5 - Data Structures), the code

while (list != NULL)
{   
    node *tmp = list-&gt;next;
    free(list);
    list = tmp;
}

is used, which does just that.

答案2

得分: -1

tl;dr 是的,只要 while (list != NULL) 就可以直接使用列表。

内存泄漏

是的,这两种方法非常不同。第二种实现会导致内存泄漏

内存泄漏是低级语言(如 C 语言)中非常常见的错误,正是因为你的程序“似乎仍然可以工作”。事实上,你可以简单地执行 list = NULL,程序仍然可以工作(尽管不正确)。但是,如果没有调用 free,内存会被占用。此外,你已经失去了对指针的跟踪,所以后续无法释放内存。这就是内存泄漏。如果只是小内存泄漏,不会有什么问题。但在大型程序中,它会耗尽计算机的 RAM。你可以通过多次调用 malloc 并检查程序的内存使用情况来测试这一点。

还可以查看 https://stackoverflow.com/questions/654754/what-really-happens-when-you-dont-free-after-malloc-before-program-termination?rq=2

你的代码

如果你的意思是 while (list != NULL) 而不是 while (ptr != null),那么我非常确定你的代码是正确的,你可以直接使用 list 而不需要 ptr(在输入所有前面的解释之后,我才意识到你可能犯了个打字错误 😭)。教师可能选择使用额外的 ptr 变量是为了与他们在其他函数中遍历链表的方式保持一致。

但根据你现在的代码,这段代码等效于一行 free(list);。除了第一个元素之外,其他元素都不会被释放。

附注:你可以使用 gcc -fsanitize=address program.c 检查内存泄漏(不适用于 mingw)。

英文:

tl;dr yes, you can use list directly, as long as while (list != NULL)

Memory leak

Yes, these two are very different. The second implementation causes a memory leak.

Memory leak is a very common bug in low level languages like c, exactly because your program "seems to work the same." In fact, you can simply do list = NULL and the program will still work (albeit not properly). However, without calling free, the memory occupied. In addition, you have lost track of the pointer, so it's impossible to free the memory later. This is a memory leak. If it's just a small leak, nothing bad will happen. In a large program, it will eat up your computer's RAM. You can try this by calling malloc a bunch of times and checking the program's memory usage.

Also check out https://stackoverflow.com/questions/654754/what-really-happens-when-you-dont-free-after-malloc-before-program-termination?rq=2

Your code

If you mean while (list != NULL) instead of while (ptr != null) then I'm pretty sure your code is correct, and you can use list directly without ptr (I only realized you might've made a typo after typing all the previous explanation 😭). The instructors might have chosen to use an extra ptr variable for consistency with how they traverse the linked list in other functions.

But with what you have now, the code is equivalent to a single line of free(list);. None of the elements except the first will be freed.

P.S. you can check for memory leak with gcc -fsanitize=address program.c (does not work with mingw).

huangapple
  • 本文由 发表于 2023年7月11日 10:10:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76658325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定