我试图销毁一个单链表,首先,我的销毁函数代码如下:
void destroy_list_v0 (SLINK *list)
{
SLINK ptr = *list;
while (NULL != *list)
{
ptr = *list;
*list = (*list)->next;
free (ptr);
}
}
函数 v0 表现完美。这是输出。
Input a number for length of the link.
init_start.
init_end & traverset_start.
The 0th element is 0.
The 1st element is 5.
The 2nd element is 93.
The 3rd element is 92.
The 4th element is 70.
The 5th element is 92.
traverse_end & destroy_start.
destroy_end & traverse_start.
traverse_end.
All operations done.
然后我觉得单指针就够了,于是我把函数调整为单指针版本:
void destroy_list_v1 (SLINK list)
{
SLINK ptr = list;
while (NULL != list)
{
ptr = list;
list = list->next;
free (ptr);
}
}
这是 v1 的输出:
Input a number for length of the link.
init_start.
init_end & traverset_start.
The 0th element is 0.
The 1st element is 27.
The 2nd element is 38.
The 3rd element is 20.
The 4th element is 66.
The 5th element is 30.
traverse_end & destroy_start.
destroy_end & traverse_start.
The 0th element is 0.
The 1st element is 32759808.
The 2nd element is 32759968.
The 3rd element is 32759936.
The 4th element is 32759904.
The 5th element is 32759872.
traverse_end.
All operations done.
为了确认销毁函数工作正常,我在链表被销毁后遍历它。我发现可以读取列表(如果是v0,则无法读取),尽管每个节点的值都已更改且不确定。我以为 v0 执行后,列表的指针指向 NULL,但 v1 执行后,它仍然指向原始地址。为了测试这个想法,我将 v0 调整为 v2:
void destroy_list_v2 (SLINK *list)
{
SLINK p_list = *list;
SLINK ptr = *list;
while (NULL != *p_list)
{
ptr = *p_list;
p_list = p_list->next;
free (ptr);
}
}
这是 v2 输出:
Input a number for length of the link.
init_start.
init_end & traverset_start.
The 0th element is 0.
The 1st element is 76.
The 2nd element is 53.
The 3rd element is 80.
The 4th element is 31.
The 5th element is 97.
traverse_end & destroy_start.
destroy_end & traverse_start.
The 0th element is 0.
The 1st element is 13860864.
The 2nd element is 13861024.
The 3rd element is 13860992.
The 4th element is 13860960.
The 5th element is 13860928.
traverse_end.
All operations done.
我认为我的分析是正确的,但它导致了新的问题。
节点结构在这里:
typedef struct tag_node
{
int elem;
struct tag_node *next;
}NODE, *SLINK; //SLINK means SINGLE LINK
我有两个问题:
1:指针'next'存储在当前指针指向的内存空间中,释放当前节点后,为什么指针'next'的内存空间仍然可以读取?指针“下一个”还活着吗?我有这个问题是因为我认为在 v1 或 v2 执行之后,它应该只是可以读取的 header 节点。
2:我toutht v1和v2破坏了整个列表,在v1或v2执行之后,为什么header的值仍然存在?我认为应该是第 1 到第 5 变成了一个不确定的数字。
这是整个代码,环境是Debian,clang:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define i_track(n) printf ("The %s's is %d.\n", #n, (n))
#define s_track(n) printf ("%s.\n", #n);
typedef struct tag_node
{
int elem;
struct tag_node *next;
}NODE, *SLINK; //SLINK means SINGLE LINK
void node_track (SLINK list);
NODE *node_generate (void);
SLINK init_list (int len);
SLINK locate_cur (SLINK list, int target_elem);
void insert_node (SLINK *list, int new_elem, int tag_elem);
SLINK traverse_list (SLINK list);
void clear_list (SLINK list);
void destroy_list_v0 (SLINK *list);
void destroy_list_v1 (SLINK list);
void destroy_list_v2 (SLINK *list);
void list_info (SLINK list, int node_elem);
int main (int argc, char *argv[])
{
int len;
SLINK list;
printf ("Input a number for length of the link.\n");
scanf ("%d", &len);
s_track(init_start);
list = init_list (len);
s_track(init_end & traverset_start);
traverse_list (list);
s_track(traverse_end & destroy_start);
// destroy_list_v0 (&list);
// destroy_list_v1 (list);
destroy_list_v2 (&list);
s_track(destroy_end & traverse_start);
traverse_list (list);
s_track(traverse_end);
s_track(All operations done);
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
NODE *node_generate (void)
{
NODE *new_node = malloc (sizeof (NODE));
if (NULL == new_node)
{
printf ("ERROR: malloc failed.\n");
exit (EXIT_FAILURE);
}
memset (new_node, 0, sizeof(NODE));
return new_node;
}
SLINK locate_cur (SLINK list, int target_elem)
{
NODE *prev, *cur;
prev = node_generate ();
cur = node_generate ();
for (prev = list, cur = list->next; NULL != cur && target_elem != cur->elem; prev = cur, cur = cur->next)
;
return cur;
}
void insert_node (SLINK *list, int new_elem, int tag_elem)
{
NODE *new_node = node_generate ();
NODE *cur = *list;
new_node->elem = new_elem;
if ((int)NULL == tag_elem)
{
new_node->next = (*list)->next;
(*list)->next = new_node;
}
else
{
*list = locate_cur (cur, tag_elem);
new_node->next = (*list)->next;
(*list)->next = new_node;
}
}
SLINK init_list (int len)
{
SLINK header = node_generate ();
srand ((unsigned) time(0));
int elem;
for (int i = 0; i < len; i++)
{
elem = rand () % 100;
if (4 == elem / 10)
{
elem = elem + 50;
}
if (4 == elem % 10)
{
elem = elem + 5;
}
if (0 == elem % 100)
{
elem = elem + 999;
}
insert_node (&header, elem, (int)NULL);
}
return header;
}
void clear_list (SLINK list)
{
for (SLINK cur = list->next; NULL != cur; )
{
cur = cur->next;
free (list->next);
list->next = cur;
}
}
void destroy_list_v0 (SLINK *list)
{
SLINK ptr = *list;
while (NULL != *list)
{
ptr = *list;
*list = (*list)->next;
free (ptr);
}
}
void destroy_list_v1 (SLINK list)
{
SLINK ptr = list;
while (NULL != list)
{
ptr = list;
list = list->next;
free (ptr);
}
}
void destroy_list_v2 (SLINK *list)
{
SLINK p_list = *list;
SLINK ptr = *list;
while (NULL != p_list)
{
ptr = p_list;
p_list = p_list->next;
free (ptr);
}
}
SLINK traverse_list (SLINK list)
{
SLINK ptr = list;
for (int node_num = 0; ptr != NULL; ptr = ptr->next)
{
list_info (ptr, node_num);
++node_num;
}
return list;
}
void list_info (SLINK list, int node_num)
{
if (1 == node_num % 10 && 11 != node_num)
{
printf ("The %dst element is %d.\n", node_num, list->elem);
}
else if (2 == node_num % 10 && 12 != node_num)
{
printf ("The %dnd element is %d.\n", node_num, list->elem);
}
else if (3 == node_num % 10 && 13 != node_num)
{
printf ("The %drd element is %d.\n", node_num, list->elem);
}
else
{
printf ("The %dth element is %d.\n", node_num, list->elem);
}
}
void node_track (NODE *flag)
{
printf ("The flag element is %d.\n", flag->elem);
}