C语言的那些小秘密之链表(二)
虽然两个指针变量存放在不同的单元,但是它们都指向同一个存储单元,所以在释放的时候只能释放一次,如果释放两次就会出错。注意切不可同时使用free(pointer_1);和 free(pointer_2);,否则将会出现内存错误。对出错原因不懂的可以参考我前面的文章《C语言的那些小秘密之指针》。这个代码和我们双链表的最大区别是它只能使用free()函数进行一次释放,而我们双链表中看似使用了两次,但实则一次而已。原因就在于我们在对头结点分配空间的时候分配的是存放data指针变量的存储空间(注意:所有的指针变量在分配的时候均分配4字节大小的存储空间,如果有什么疑惑可以参考我之前写的《C语言的那些小秘密之指针》)。所以释放的时候也是释放的存放指针变量data的存储空间,并没有释放掉指针变量data所指向的存储空间。所以在释放data指向的存储空间时,我们只需要在main()函数中对stu[i]所指向的存储空间使用free()函数即可,因为data和它指向的是同一个存储空间。
本文引用地址:https://www.eepw.com.cn/article/272382.htm接下来我们来添加一个在头结点添加结点的模块。
#include
#include
typedef enum _DListReturn
{
DLIST_RETURN_OK,
DLIST_RETURN_FAIL
}DListReturn;
typedef struct _DStu
{
int score;
}DStu;
typedef struct _DListNode
{
struct _DListNode* prev;
struct _DListNode* next;
DStu* data;
}DListNode;
typedef struct _DList
{
DListNode* head;
}DList;
typedef DListReturn (*DListPrintFunction)(void* data);
DListNode* dlist_node_create(void* data)
{
DListNode* node;
if((node = (DListNode*) malloc(sizeof(DListNode)))==NULL)
{
printf("分配空间失败!");
exit(0);
}
if(node != NULL)
{
node->prev = NULL;
node->next = NULL;
node->data =(DStu*)data;
}
return node;
}
DList* dlist_head_create(void)
{
DList* thiz;
if((thiz = (DList*)malloc(sizeof(DList)))==NULL)
{
printf("分配空间失败!");
exit(0);
}
if(thiz != NULL)
{
thiz->head = NULL;
}
return thiz;
}
DListReturn dlist_append(DList* thiz, void* data)
{
DListNode* node = NULL;
DListNode* cursor = NULL;
if((node = dlist_node_create(data)) == NULL)
{
return DLIST_RETURN_FAIL;
}
if(thiz->head == NULL)
{
thiz->head = node;
return DLIST_RETURN_OK;
}
cursor = thiz->head;
while(cursor != NULL && cursor->next != NULL)
{
cursor = cursor->next;
}
cursor->next = node;
node->prev = cursor;
return DLIST_RETURN_OK;
}
DListReturn dlist_prepend(DList* thiz, void* data)
{
DListNode* node = NULL;
DListNode* cursor = NULL;
if((node = dlist_node_create(data)) == NULL)
{
return DLIST_RETURN_FAIL;
}
if(thiz->head == NULL)
{
thiz->head = node;
return DLIST_RETURN_OK;
}
cursor = thiz->head;
if(thiz->head == cursor)
thiz->head = node;
node->next = cursor;
cursor->prev = node;
return DLIST_RETURN_OK;
}
DListReturn dlist_print(DList* thiz, DListPrintFunction print)
{
DListNode* iter = thiz->head;
while(iter != NULL)
{
print(iter->data);
iter = iter->next;
}
printf("n");
return DLIST_RETURN_OK;
}
DListReturn print_int(void* data)
{
DStu* ss=(DStu*)data;
printf("%dt ", ss->score);
return DLIST_RETURN_OK;
}
DListReturn dlist_node_destroy(DListNode* node)
{
if(node != NULL)
{
node->next = NULL;
node->prev = NULL;
free(node);
}
return DLIST_RETURN_OK;
}
DListReturn dlist_destroy(DList* thiz)
{
DListNode* iter = thiz->head;
DListNode* next = NULL;
while(iter != NULL)
{
next = iter->next;
dlist_node_destroy(iter);
iter = next;
}
thiz->head = NULL;
free(thiz);
return DLIST_RETURN_OK;
}
int main(int argc, char* argv[])
{
int i = 0;
DList* dlist = dlist_head_create();
for(i = 0; i < 7; i++)
{
DStu* stu =(DStu*) malloc(sizeof(DStu));
stu->score = i;
dlist_append(dlist, (void*)stu);
}
for(i = 0; i < 7; i++)
{
DStu* stu =(DStu*) malloc(sizeof(DStu));
stu->score = i;
dlist_prepend(dlist, (void*)stu);
}
dlist_print(dlist, print_int);
dlist_destroy(dlist);
return 0;
}
我们在上一段代码添加了红色部分代码后,使得其在已经生成的双链表的头结点处添加结点,运行结果如下:

6 5 4 3 2 1 0 0 1 2
3 4 5 6
Press any key to continue
可以看出结果与我们的要求完全符合。如果你认真分析了代码的话你就会发现,我们的两种添加方式中有公共代码出现,那就说明我们的代码可以继续改进,把公共代码放到一个函数中,读者可以另外编写一个函数来实现,使得我们编写的代码得到充分的利用。
篇幅似乎有些过长了,接下来我就不再一一讲解了,我在这里只是想起一个引路的作用,读者完全可以在此基础之上继续编写双链表其余部分的功能,其他的功能模块读者可以在此基础上一一添加上去,到下一篇的时候我们将走进linux内核链表,继续链表之旅的最后一站。由于本人水平有限,博客中的不妥或错误之处在所难免,殷切希望读者批评指正。同时也欢迎读者共同探讨相关的内容,如果乐意交流的话请留下你宝贵的意见。
评论