1. 内存泄漏
定义:内存泄漏是指程序在运行过程中动态分配的内存未被释放,导致可用内存逐渐减少,最终可能导致程序崩溃或系统性能下降。
原因:(1)忘记释放不再使用的内存。
(2)失去对动态分配内存的引用(例如,指针被覆盖或丢失)。
(3)循环引用。
解决方法:
(1)确保每次动态分配内存后都有相应的释放操作。
(2)使用智能指针来自动管理内存。
(3)使用内存分析工具(如 Valgrind)检测内存泄漏。
2. 内存碎片
定义:内存碎片是指在动态内存分配过程中,由于频繁的分配和释放操作,导致内存中出现许多小的、不可用的空闲块,从而降低了内存的使用效率。
类型:(1)外部碎片:指在内存中存在多个小的空闲块,无法满足大块内存的分配请求。
(2)内部碎片:指分配的内存块大于实际需要的内存,导致未使用的内存浪费。
解决方法:(1)使用合适的内存分配策略(如最佳适应、最差适应、首次适应等)。
(2)定期整理内存,合并相邻的空闲块。
(3)使用内存池等技术来减少频繁的分配和释放。
二、双向链表
1. 单向链表和双向链表的比较
特性 单向链表 双向链表
结构 每个节点包含数据和指向下一个节点的指针 每个节点包含数据、指向下一个节点和前一个节点的指针
遍历方向 只能从头到尾遍历 可以从头到尾和尾到头遍历
内存使用 较少,只有一个指针 较多,两个指针
插入和删除操作 在头部或尾部插入/删除较快,但在中间插入/删除需要遍历 在任意位置插入/删除都较快,尤其是在已知节点的情况下
实现复杂度 较简单 较复杂
2. 使用场景
单向链表:适用于只需要单向遍历的场景,如栈的实现、简单的队列等。
双向链表:适用于需要频繁插入和删除操作的场景,如浏览器的历史记录、音乐播放器的播放列表等。
3.单向链表的插入排序,快慢指针和链表倒置:
Link_Node_t *seek_counterback_node2(Link_t *plink,int k)//快慢指针法寻找倒数链表;
{
if(plink->phead == NULL)
{
return NULL;
}
else
{
Link_Node_t *p = plink->phead;
Link_Node_t *p2 = p;
for(int i = 0;i<k;++i)
{
if(p==NULL)
{
return NULL;
}
p = p->pnext;
}
while(p!=NULL)
{
p = p->pnext;
p2 = p2->pnext;
}
return p2;
}
}
int reversal_link(Link_t *plink) //链表倒置
{
if(plink->phead == NULL)
{
return -1;
}
Link_Node_t *pinsert = NULL;
Link_Node_t *ptmp = plink->phead;
plink->phead = NULL;
while(ptmp!=NULL)
{
pinsert = ptmp;
ptmp = ptmp->pnext;
pinsert->pnext = plink->phead;
plink->phead = pinsert;
}
return 0;
}
void sort_link(Link_t *plink)//插入排序
{
Link_Node_t *ptmp = plink->phead->pnext;
plink->phead->pnext = NULL;
Link_Node_t *p = plink->phead;
while(ptmp)
{
Link_Node_t *pinsert = ptmp;
ptmp = ptmp->pnext;
if(pinsert->data <= plink->phead->data)
{
pinsert->pnext = plink->phead;
plink->phead = pinsert;
}
else
{
while(p->pnext != NULL && p->pnext->data < pinsert->data)
{
p = p->pnext;
}
pinsert->pnext = p->pnext;
p->pnext = pinsert;
}
}
}
4.双向链表(头插尾插,头删尾删,寻找,销毁)
DLink_t *doulink_create()
{
DLink_t *doulink = (DLink_t *)malloc(sizeof(DLink_t));
if(doulink == NULL)
{
perror("doulink creat fail\n");
return NULL;
}
doulink->clen = 0;
doulink->phead = NULL;
pthread_mutex_init(&doulink->mutex,NULL);
return doulink;
}
int push_doulink_head(DLink_t *doulink,DataType data)
{
DLink_Node_t *pnode = (DLink_Node_t *)malloc(sizeof(DLink_Node_t));
if (NULL == pnode)
{
perror("fail malloc\n");
return -1;
}
pnode->data = data;
pnode->ppre = NULL;
pnode->pnext = NULL;
if (doulink->phead == NULL)
{
doulink->phead = pnode;
}
else
{
pnode->pnext = doulink->phead;
doulink->phead->ppre = pnode;
doulink->phead = pnode;
}
doulink->clen++;
return 0;
}
int push_doulink_tail(DLink_t *doulink,DataType data)
{
DLink_Node_t *pnode = (DLink_Node_t *)malloc(sizeof(DLink_Node_t));
if(NULL == pnode)
{
perror("fail malloc\n");
}
pnode->data = data;
pnode->ppre = NULL;
pnode->pnext = NULL;
DLink_Node_t *p = doulink->phead;
if (doulink->phead == NULL)
{
doulink->phead = pnode;
}
else
{
while(p->pnext != NULL)
{
p = p->pnext;
}
p->pnext = pnode;
pnode->ppre = p;
}
doulink->clen++;
}
void traverse_link(DLink_t *doulink,int dir)//遍历
{
DLink_Node_t *p = doulink->phead;
if(dir)
{
while(p != NULL)
{
printf("%d %s %d\n",p->data.id, p->data.name,p->data.score);
p = p->pnext;
}
}
else
{
while(p->pnext != NULL)
{
p = p->pnext;
}
while(p != NULL)
{
printf("%d %s %d\n",p->data.id, p->data.name,p->data.score);
p = p->ppre;
}
}
}
int pop_doulink_head(DLink_t *doulink)
{
if(doulink->phead == NULL)
{
return 0;
}
DLink_Node_t *p = doulink->phead->pnext;
free(doulink->phead);
if(p != NULL)
{
p->ppre = NULL;
}
doulink->phead = p;
doulink->clen--;
return 1;
}
int pop_doulink_tail(DLink_t *doulink)
{
if(NULL == doulink->phead)
{
return 0;
}
else if(doulink->phead->pnext == NULL)
{
pop_doulink_head(doulink);
}
else
{
DLink_Node_t *p = doulink->phead;
while(p->pnext->pnext != NULL)
{
p = p->pnext;
}
free(p->pnext);
p->pnext = NULL;
doulink->clen--;
return 1;
}
}
DLink_Node_t *seek_doulink_node(DLink_t *doulink,char *name)
{
DLink_Node_t *p = doulink->phead;
if(p == NULL)
{
return NULL;
}
while(p != NULL)
{
if(strcmp(p->data.name,name)==0)
{
return p;
}
p = p->pnext;
}
return NULL;
}
int change_doulink_node(DLink_t *doulink,char *name,int newscore)
{
DLink_Node_t *p = doulink->phead;
if(p==NULL)
{
return -1;
}
while(p != NULL)
{
if(strcmp(p->data.name,name)==0)
{
p->data.score = newscore;
}
p = p->pnext;
}
return 0;
}
int destory_link(DLink_t *doulink)//销毁链表
{
while (doulink->phead != NULL) { // 当链表不为空时
pop_doulink_head(doulink); // 逐个删除头节点
}
free(doulink); // 释放链表结构体
return 0;
DLink_Node_t *p = doulink->phead;
while(p != NULL)
{
pop_doulink_head(doulink);
}
free(doulink);
return 0;
}
三、内核链表(是一个有头双向循环链表)
1.内核提供的两个宏
(1) offsetof : 获取结构体成员到结构体开头的偏移量;
(2) contianer_of : 通过偏移量获取结构体首地址;