检查内存泄漏:
执行命令:valgrinid ./a.out
检查 malloc 和free, 的次数。
GDB
linux 软件开放人员,必须会的4个工具
gcc 编译器 把源文件转换为可执行程序
vim linux 下文本编辑器。
gdb 调试器,检查程序的逻辑错误
makefile 工程管理工具
gdb的常用命令

调试的步骤
gdb 一般调试
- 编译自己代码的时候假如调试选择 -g 给a.out 假如调试信息
gcc -g 1.c
具体操作使用:

顺序表和链表 优缺点
存储方式:
顺序表是一段连续的存储单元。
链表是逻辑结构连续物理结构(在内存中的表现形式)不连续。
时间性能:
查找 顺序表O(1)
链表 O(n)
插入和删除 :
顺序表 O(n)
链表 O(1)
空间性能:
顺序表 需要预先分配空间,大小固定。
链表, 不需要预先分配,大小可变,动态分配。
顺序表的主要函数;
bash
#include "seqlist.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/**
* @brief 创建一个线性顺序表
*
* @param len 顺序表的容量
* @return SeqList* 返回顺表表头指针
如果失败返回 NULL
*/
SeqList *CreateSeqList(int len)
{
//创建表头
SeqList *sq = malloc(sizeof(SeqList));
if (NULL == sq)
{
printf("CreateSeqList malloc1 error\n");
return NULL;
}
sq->head = malloc(sizeof(DATATYPE) * len);
if (NULL == sq->head)
{
printf("CreateSeqList malloc2 error\n");
return NULL;
}
sq->tlen = len;
sq->clen = 0;
return sq;
}
int ShowSeqList(SeqList *list)
{
int len = GetSizeSeqList(list);
int i = 0;
for (i = 0; i < len; i++)
{
printf("name:%s age:%d sex:%c,score:%d\n", list->head[i].name,
list->head[i].age, list->head[i].sex, list->head[i].score);
}
}
/**
* @brief 尾增数据元素
*
* @param list 需要被操作的顺序表的指针
* @param data 需要新增的数据的指针
* @return int 0 表示成功 1表示失败
*/
int InsertTailSeqList(SeqList *list, DATATYPE *data)
{
if (IsFullSeqList(list))
{
printf("list is full\n");
return 1;
}
memcpy(&list->head[list->clen], data, sizeof(DATATYPE));
list->clen++;
return 0;
}
int IsFullSeqList(SeqList *list)
{
return list->clen == list->tlen;
}
int IsEmptySeqList(SeqList *list)
{
return 0 == list->clen;
}
/**
* @brief 按位置插入元素
*
* @param list 待操作的顺序表表头指针
* @param data 指向待插入顺序表的数据的指针
* @param pos 需要插入位置 的下标
* @return int 0 表示成功 1失败,表满 2 pos 不合适
*/
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)
{
if (IsFullSeqList(list))
{
printf("list is full");
return 1;
}
int len = GetSizeSeqList(list);
if (pos < 0 || pos > len)
{
printf("pos error\n");
return 2;
}
int i = 0;
//整体的下移
for (i = list->clen - 1; i >= pos; i--)
{
// list->head[i+1]=list->head[i];
memcpy(&list->head[i + 1], &list->head[i], sizeof(DATATYPE));
}
memcpy(&list->head[pos], data, sizeof(DATATYPE));
list->clen++;
return 0;
}
/**
* @brief 根据名字查找 人员
*
* @param list 待操作的顺序表的指针
* @param name 需要查找的人名
* @return int -1 表示失败 >=0 找到的下标
*/
int FindSeqList(SeqList *list, char *name)
{
if (IsEmptySeqList(list))
{
return -1;
}
int len = GetSizeSeqList(list);
int i = 0;
for (i = 0; i < len; i++)
{
if (0 == strcmp(name, list->head[i].name))
{
return i;
}
}
return -1;
}
/**
* @brief 根据名字修改一个人的信息
*
* @param list 待操作的顺序表的指针
* @param oldname 需要被修改的人名
* @param newdata 替换旧人员的信息
* @return int 0 成功 1 失败
*/
int ModifySeqList(SeqList *list, char *oldname, DATATYPE *newdata)
{
int ret = FindSeqList(list, oldname);
if (-1 == ret)
{
printf("modify error\n");
return 1;
}
// list->head[ret] = *newdata;
memcpy(&list->head[ret], newdata, sizeof(DATATYPE));
return 0;
}
/**
* @brief 在顺序表中 根据名字删除一个人
*
* @param list 待操作的顺序表的指针
* @param name 需要被删除的人名
* @return int 0 表示成功 1失败
*/
#### 面试常考 !!!
int DeleteSeqList(SeqList *list, char *name)
{
int ret = FindSeqList(list, name);
if (-1 == ret)
{
printf("del error\n");
return 1;
}
int len = GetSizeSeqList(list);
int i = 0;
for (i = ret; i < len - 1; i++)
{
// list->head[i] = list->head[i + 1];
memcpy(&list->head[i], &list->head[i + 1], sizeof(DATATYPE));
}
list->clen--;
return 0;
}
/**
* @brief 清空顺序表
*
* @param list 待操作的顺序表的指针
* @return int 0
*/
int ClearSeqList(SeqList *list)
{
list->clen = 0;
return 0;
}
/**
* @brief 获得顺序表,有效元素的个数
*
* @param list 需要被操作的顺序表的指针
* @return int >=0 返回的是元素的个数
*/
int GetSizeSeqList(SeqList *list)
{
return list->clen;
}
int DestroySeqList(SeqList *list)
{
free(list->head); //释放数组
free(list); //释放表头
return 0;
}
单项链表的函数:
bash
#include "linklist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief Create a Link List object 创建一个单向链表头结构
*
* @return LinkList* 指向单向链表表头结构的指针
*/
LinkList *CreateLinkList()
{
LinkList *ll = malloc(sizeof(LinkList));
if (NULL == ll)
{
printf("CreateLinkList malloc error\n");
return NULL;
}
ll->head = NULL;
ll->clen = 0;
return ll;
}
/**
* @brief 单向链表的头插操作
*
* @param list 待操作的链表
* @param data 需要新增的数据
* @return int 0 成功 1 失败
*/
int InsertHeadLinkList(LinkList *list, DATATYPE *data)
{
LinkNode *newnode = malloc(sizeof(LinkNode));
if (NULL == newnode)
{
printf("InsertHeadLinkList malloc error\n");
return 1;
}
memcpy(&newnode->data, data, sizeof(DATATYPE));
newnode->next = NULL;
newnode->next = list->head;
list->head = newnode;
list->clen++;
return 0;
}
/**
* @brief 在链表的最后新增元素
*
* @param list 待操作的链表
* @param data 需要新增的数据
* @return int 0 成功 1 失败
*/
int InsertTailLinkList(LinkList *list, DATATYPE *data)
{
if (IsEmptyLinkList(list))
{
return InsertHeadLinkList(list, data);
}
LinkNode *newnode = malloc(sizeof(LinkNode));
if (NULL == newnode)
{
printf("InsertTailLinkList malloc error\n");
return 1;
}
memcpy(&newnode->data, data, sizeof(DATATYPE));
newnode->next = NULL;
LinkNode *tmp = list->head;
while (tmp->next)
{
tmp = tmp->next;
}
tmp->next = newnode;
list->clen++;
return 0;
}
/**
* @brief 显示单向链表中的数据
*
* @param list 待操作的单向链表 表头指针
* @return int 0 表示成功
*/
int ShowLinkList(LinkList *list)
{
LinkNode *tmp = list->head;
while (NULL != tmp)
{
printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
tmp->data.age, tmp->data.sex, tmp->data.score);
tmp = tmp->next; // i++
}
return 0;
}
/**
* @brief 按照名字查找一个节点
*
* @param list 需要被查找的链表
* @param name 需要被查找的用户的名字
* @return LinkNode* !=NULL 成功 NULL 失败
*/
LinkNode *FindLinkList(LinkList *list, char *name)
{
LinkNode *tmp = list->head;
int len = GetSizeLinkList(list);
int i = 0;
for (i = 0; i < len; i++)
{
if (0 == strcmp(tmp->data.name, name))
{
return tmp;
}
tmp = tmp->next;
}
return NULL; // (void*)0
}
面试常考!!!!!!
int DeleteLinkList(LinkList *list, char *name)
{
if (IsEmptyLinkList(list))
{
printf("DeleteLinkList error\n");
return 1;
}
LinkNode *tmp = NULL;
LinkNode *prev = NULL;
// 头删
if (0 == strcmp(name, list->head->data.name))
{
tmp = list->head;
list->head = list->head->next;
free(tmp);
list->clen--;
return 0;
}
else
{
tmp = list->head;
prev = list->head;
while (1)
{
tmp = tmp->next;
if (NULL == tmp)
{
break;
}
if (0 == strcmp(tmp->data.name, name))
{
prev->next = tmp->next;
free(tmp);
list->clen--;
return 0;
}
prev = tmp;
}
}
return 1;
}
/**
* @brief
*
* @param list 根据名字修改节点的内容
* @param name 需要被修改的用户名
* @param newdata 要替换老用户的数据
* @return int 0 成功 1失败
*/
int ModifyLinkList(LinkList *list, char *name, DATATYPE *newdata)
{
LinkNode *ret = FindLinkList(list, name);
if (NULL == ret)
{
printf("modify error\n");
return 1;
}
memcpy(&ret->data, newdata, sizeof(DATATYPE));
return 0;
}
/**
* @brief 释放链表占用的内存 (表头+节点)
*
* @param list 需要释放的链表的表头指针
* @return int 0 成功 !0 失败
*/
int DestroyLinkList(LinkList **list)
{
LinkNode *tmp = NULL;
while (1)
{
tmp = (*list)->head;
if (NULL == tmp)
{
break;
}
(*list)->head = (*list)->head->next;
free(tmp);
}
free(*list);
*list = NULL;
return 0;
}
int IsEmptyLinkList(LinkList *list)
{
return 0 == list->clen;
}
int GetSizeLinkList(LinkList *list)
{
return list->clen;
}
/**
* @brief 单向链表的逆序
*
* @param list 待操作的链表
*/
void RevertLinkList(LinkList *list)
{
LinkNode *prev = NULL;
LinkNode *tmp = list->head;
LinkNode *next = tmp->next;
while (1)
{
tmp->next = prev;
prev = tmp;
tmp = next;
if (NULL == tmp)
{
break;
}
next = next->next;
}
list->head = prev;
}
/**
* @brief 查找链表中的 中间节点
*
* @param list 需要被操作的链表
* @return LinkNode* NULL 失败 !NULL 找到的中间节点
*/
LinkNode *FindMidLinkList(LinkList *list)
{
LinkNode *fast = list->head;
LinkNode *slow = list->head;
while (fast)
{
fast = fast->next; // fast = 1000
if (NULL == fast)
{
break;
}
slow = slow->next;
fast = fast->next;
}
return slow;
}
/**
* @brief 查找链表倒数的第k个节点
*
* @param list 待操作的链表表头指针
* @param k 倒数第k个
* @return LinkNode* NULL 没有找到 , !NULL 成功
*/
LinkNode *FindLastKLinkList(LinkList *list, int k)
{
LinkNode *slow = list->head;
LinkNode *fast = list->head;
int i = 0;
for (i = 0; i < k; i++)
{
if (NULL == fast)
{
return NULL;
}
fast = fast->next;
}
while (fast)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
双向链表的函数:
bash
#include "doulink.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/**
* @brief 创建双向链表的表头结构
*
* @return 成功 返回指向表头结构的指针 失败返回NULL
*/
DouLinkList *CreateDouLinkList()
{
DouLinkList *dl = malloc(sizeof(DouLinkList)); // 获取链表的内存空间
if (NULL == dl)
{
printf("CreateDouLinkList malloc error\n");
return NULL;
}
dl->head = NULL; 定义头节点
dl->clen = 0;
return dl;
}
/**
* @brief 双向链表的头插
*
* @param dl 待操作的双向链表
* @param data 需要插入的数据
* @return int 0 成功 1失败
*/
int InsertHeadDouLinkList(DouLinkList *dl, DATATYPE *data)
{
DouLinkNode *newnode = malloc(sizeof(DouLinkNode));
if (NULL == newnode)
{
printf("InsertHeadDouLinkList malloc error\n");
return 1;
}
memcpy(&newnode->data, data, sizeof(DATATYPE));
newnode->next = NULL;
newnode->prev = NULL;
if (!IsEmptyDouLinkList(dl))
{
newnode->next = dl->head;
dl->head->prev = newnode;
}
dl->head = newnode;
dl->clen++;
return 0;
}
int ShowDouLinkList(DouLinkList *dl, DIRECT dir(判断刷新的正反方向))
{
DouLinkNode *tmp = dl->head;
if (DIR_FORWARD == dir) //因为插入顺序的特殊,正向输出反而是输出倒叙
{
while (tmp)
{
printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
tmp->data.age, tmp->data.sex, tmp->data.score);
tmp = tmp->next;
}
}
else 另一种输出方式
{
while (tmp->next)
{
tmp = tmp->next;
}
while (tmp)
{
printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
tmp->data.age, tmp->data.sex, tmp->data.score);
tmp = tmp->prev;
}
}
}
int InserTailDouLinkList(DouLinkList *dl, DATATYPE *data) 插入最后一个节点
{
if (NULL == dl) // 判断结构体指针是否为空
{
return 1;
}
if (IsEmptyDouLinkList(dl)) //判断结构体本身是否为空
{
return InsertHeadDouLinkList(dl, data); //把数据放在头节点的位置便是尾节点
}
else
{
DouLinkNode *tmp = dl->head; //定义结构体数组指针
while (tmp->next)
{
tmp = tmp->next;
} 循环到最后一个节点
DouLinkNode *newnode = malloc(sizeof(DouLinkNode)); //开辟新数据内存空间
if (NULL == newnode) 开始进行判断
{
printf("InserTailDouLinkList malloc error\n");
return 1;
}
memcpy(&newnode->data, data, sizeof(DATATYPE)); 先把数据复制在新的节点之上
newnode->next = NULL; 前后置空
newnode->prev = NULL;
tmp->next = newnode; //最后节点的下一个指向 新节点
newnode->prev = tmp; //新节点的前一个指向新节点
}
dl->clen++;
return 0;
}
/**
* @brief 根据名字查找节点
*
* @param dl 需要被操作的链表
* @param name 需要查找的用户名
* @return DouLinkNode* NULL 失败 !=NULL 成功
*/
DouLinkNode *FindDouLinkList(DouLinkList *dl, char *name)
{
DouLinkNode *tmp = dl->head;
while (NULL != tmp)
{
if (0 == strcmp(tmp->data.name, name))
{
return tmp;
}
tmp = tmp->next; //指向下一个开始寻找,直到找到为止
}
return NULL;
}
/**
* @brief 根据名字修改 信息
*
* @param dl 需要操作的链表的指针
* @param name 需要被修改信息的用户名
* @param newdata 需要写入的新数据
* @return int 0 成功 1 失败
*/
int ModifyDouLinkList(DouLinkList *dl, char *name, DATATYPE *newdata)
{
if (NULL == dl) //判断链表是否存在
{
return 1;
}
DouLinkNode *tmp = FindDouLinkList(dl, name);
if (NULL == tmp)
{
printf("modify error\n");
return 1;
}
memcpy(&tmp->data, newdata, sizeof(DATATYPE)); //直接进行复制
return 0;
}
/**
* @brief 根据删除名字删除一个节点
*
* @param dl 需要被操作的链表
* @param name 需要被删除的用户名
* @return int 0 成功, 1 失败
*/
int DeleteDouLinkList(DouLinkList *dl, char *name)
{
DouLinkNode *tmp = FindDouLinkList(dl, name);
if (NULL == tmp)
{
return 1;
}
//删除的就是第一个人
if (dl->head == tmp)
{
dl->head = dl->head->next;
dl->head->prev = NULL;
}
else
{
if (tmp->next != NULL) //不是最后一个节点
{
tmp->next->prev = tmp->prev;
}
tmp->prev->next = tmp->next;
}
free(tmp);
dl->clen--;
return 0;
}
int IsEmptyDouLinkList(DouLinkList *dl)
{
return NULL == dl->head;
}
GetSizeDouLinkList(DouLinkList *dl)
{
return dl->clen;
}
/**
* @brief 销毁链表,释放链表占用的内存空间
*
* @param dl 需要被操作的链表
* @return int 0 成功 1失败
*/
int DestroyDouLinkList(DouLinkList *dl)
{
if (NULL == dl) // 判断链表是否为空
{
return 1;
}
DouLinkNode *tmp = dl->head;
while (tmp)
{
dl->head = dl->head->next; //先保存下一个节点的位置
free(tmp); //释放本次的节点
tmp = dl->head; //指向下一个节点
} //如此循环达到释放所有节点的目的
free(dl);
return 0;
}
int RevertDouLinkList(DouLinkList *dl) 倒置
{
DouLinkNode* prev = NULL; //链表的头节点反转后没有前驱,没有尾节点
DouLinkNode* tmp = dl->head; //确定各个指针的初始位置
DouLinkNode* next = tmp->next; //确定指针的初始指向
while (tmp)
{
tmp->next = prev; //开始逆序,把后放前
tmp->prev = next; //把前方后
prev = tmp; //指针开始后移
tmp = next;
if (NULL == tmp)
{
break;
}
next = next->next; //后移结束
}
dl->head = prev; //最后把头节点倒置放在最后一个
return 0;
}