最近想對自己的知識和技能做一個總結,看到有人在博客上說,最好的知識總結,就是將知識固化,所謂的固化,就是把所學的知識記錄下來,或者寫成筆記或者寫成博客。最近也想實踐一下,就從寫博客開始,之前也把學習的過程通過學習筆記的形式寫成博客,回頭看一下還是有很多好處的,一來作爲一種知識分享,讓想學習同樣知識的同學可以一起學習,二來可以作爲自己學習的回顧,增加自己的學習效果。
總之,不管是學習還是做別的事情,都不能光想,落到實踐上比什麼都重要,尤其是做技術,動手能力非常重要。昨天自己動手寫了一個通用的鏈表庫,這裏將代碼貼出來,寫的不對的地方還請大俠幫忙指正:
頭文件list.h:
/***********************************************************
文件名:list.h
作者:Jerry
日期:2017年04月
轉發或拷貝請將這段註釋一起拷貝
***********************************************************/
#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED
#ifdef __cplusplus
extern "C"{
#endif
/*定義錯誤碼*/
enum{
LIST_OK = 0, //成功
LIST_ERR = 1 //失敗
};
typedef struct tagNode{
struct tagNode *pPrev;
struct tagNode *pNext;
void *data;
}LIST_NODE_S;
typedef struct tagList{
LIST_NODE_S *pHead;
LIST_NODE_S *pTail;
unsigned int count;
}LIST_S;
/*迭代器結構*/
typedef LIST_NODE_S LIST_ITER_S;
typedef void(*ListDataFreeFunc)(void*);
/**************************************
功能:初始化空的鏈表
參數:
返回值:指向空鏈表的指針
**************************************/
extern LIST_S *List_Api_New();
/*****************************************
功能:釋放LIST_S結構鏈表,對每一個鏈表結點調用pFunc釋放內存
參數:
LIST_S *pList, //鏈表指針
ListDataFreeFunc pFunc //結點釋放函數
返回值:void
******************************************/
extern void List_Api_FreeEx(LIST_S *pList, ListDataFreeFunc pFunc);
/***************************************************************
功能:向鏈表尾部插入數據
參數:
LIST_S *pList //要插入數據的鏈表,不能爲NULL
void *data //要插入的數據,不區分類型,需要用戶申請內存
返回值: 插入成功返回LIST_OK,失敗返回非LIST_ERR
*******************************************************************/
extern int List_Api_Append(LIST_S *pList, void *data);
/************************************************************
功能:獲取指向鏈表第一個元素的迭代器指針
參數:
LIST_S *pList //要操作的鏈表
返回值:指向第一個元素的迭代器指針
*************************************************************/
extern LIST_ITER_S *List_Api_Begin(LIST_S *pList);
/************************************************************
功能:獲取指向鏈表最後一個元素的迭代器指針
參數:
LIST_S *pList //要操作的鏈表
返回值:指向最後一個元素的迭代器指針
*************************************************************/
extern LIST_ITER_S *List_Api_Last(LIST_S *pList);
/***********************************************************
功能:獲取當前迭代器位置的數據
參數:
LIST_ITER_S *pIter //當前迭代器指針
返回值:void *
************************************************************/
extern void *List_Api_GetData(LIST_ITER_S *pIter);
/**********************************************************
功能:獲取當前迭代器的前一個迭代器指針
參數:
LIST_ITER_S *pIter
返回值:LIST_ITER_S *
***********************************************************/
extern LIST_ITER_S *List_Api_Previous(LIST_ITER_S *pIter);
/**********************************************************
功能:獲取當前迭代器的後一個迭代器指針
參數:
LIST_ITER_S *pIter
返回值:LIST_ITER_S *
***********************************************************/
extern LIST_ITER_S *List_Api_Next(LIST_ITER_S *pIter);
/*********************************************************
功能:刪除當前迭代器指向位置的元素
參數:
LIST_S *pList //要操作的鏈表,不能爲NULL
LIST_ITER_S *pIter //當前迭代器
返回值:下一個迭代器指針
***********************************************************/
extern LIST_ITER_S *List_Api_Delete(LIST_S *pList, LIST_ITER_S *pIter);
/*********************************************************
功能:獲取當前鏈表長度
參數:LIST_S *pList //要計算長度的鏈表
返回值:unsigned int
**********************************************************/
extern unsigned int List_Api_GetCount(LIST_S *pList);
#define List_Api_Free(p) do{if(p) free(p); p = NULL;}while(0)
#ifdef __cplusplus
}
#endif
#endif // LIST_H_INCLUDED
源文件 list.c:
#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
LIST_S *List_Api_New(){
LIST_S *pList;
pList = (LIST_S *)malloc(sizeof(LIST_S));
if(NULL != pList) memset(pList, 0, sizeof(LIST_S));
return pList;
}
void List_Api_FreeEx(LIST_S *pList, ListDataFreeFunc pFunc){
LIST_ITER_S *pHead, *pNext;
if(!pList) return;
assert(pFunc != NULL);
pHead = pList->pHead;
while(pHead){
pNext = pHead->pNext;
pFunc(pHead->data);
pHead = pNext;
}
pList->pHead = NULL;
pList->pTail = NULL;
pList->count = 0;
List_Api_Free(pList);
}
int List_Api_Append(LIST_S *pList, void *data){
LIST_NODE_S *pNode;
assert(pList != NULL);
pNode = (LIST_NODE_S *)malloc(sizeof(LIST_NODE_S));
if(NULL == pNode){
return LIST_ERR;
}
memset(pNode, 0, sizeof(LIST_NODE_S));
pNode->data = data;
if(pList->pHead == NULL){
pList->pHead = pNode;
pList->pTail = pList->pHead;
}
else {
//掛接結點
pList->pTail->pNext = pNode;
pNode->pPrev = pList->pTail;
//更新鏈表尾結點
pList->pTail = pList->pTail->pNext;
}
pList->count ++;
return LIST_OK;
}
void *List_Api_GetData(LIST_ITER_S *pIter){
assert(pIter != NULL);
return pIter->data;
}
LIST_ITER_S *List_Api_Begin(LIST_S *pList){
if(!pList) return NULL;
return (LIST_ITER_S*)(pList->pHead);
}
LIST_ITER_S *List_Api_Last(LIST_S *pList){
if(!pList) return NULL;
return (LIST_ITER_S*)(pList->pTail);
}
LIST_ITER_S *List_Api_Previous(LIST_ITER_S *pIter){
assert(pIter !=NULL);
return pIter->pPrev;
}
LIST_ITER_S *List_Api_Next(LIST_ITER_S *pIter){
assert(pIter != NULL);
return pIter->pNext;
}
LIST_ITER_S *List_Api_Delete(LIST_S *pList, LIST_ITER_S *pIter){
LIST_ITER_S *pHead = NULL;
LIST_ITER_S *pTail = NULL;
if(!pList) return NULL;
assert(pIter != NULL);
pHead = pList->pHead;
pTail = pList->pTail;
if(pIter == pHead){
pList->pHead = pIter->pNext;
pList->pHead->pPrev = NULL;
pList->count --;
pIter->pPrev = NULL;
pIter->pNext = NULL;
return pList->pHead;
}
if(pIter == pTail){
pList->pTail = pList->pTail->pPrev;
pList->pTail->pNext = NULL;
pList->count --;
pIter->pPrev = NULL;
pIter->pNext = NULL;
return NULL;
}
while(pHead != pIter && pHead != pTail){
pHead = pHead->pNext;
}
if(pHead == pTail){
return NULL;
}
pHead = pIter->pPrev->pNext = pIter->pNext;
pIter->pNext->pPrev = pIter->pPrev;
pList->count --;
pIter->pNext = NULL;
pIter->pPrev = NULL;
return pHead;
}
unsigned int List_Api_GetCount(LIST_S *pList){
if(!pList) return 0;
return pList->count;
}
下面的這段代碼可以對上面的接口進行測試:
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct testData{
char *name;
int age;
}STUDENT_S;
static STUDENT_S *Student_New(char *name, int age){
STUDENT_S *stu;
stu = (STUDENT_S*)malloc(sizeof(STUDENT_S));
if(!stu) return NULL;
memset(stu, 0, sizeof(STUDENT_S));
stu->name = strdup(name);
stu->age = age;
return stu;
}
static void Student_Free(STUDENT_S *pStu){
if(!pStu) return ;
if(pStu->name) free(pStu->name);
free(pStu);
}
int main(int argc, char **argv){
int *val = NULL, i;
int iRet;
STUDENT_S students[] = {
{"xiaoming", 15},
{"xiaohua", 16},
{"xiaofang", 16}
};
LIST_ITER_S *pstIter = NULL;
LIST_S *pList = List_Api_New();
if(!pList){
fprintf(stderr, "out of memory");
exit(1);
}
for(i = 0; i < sizeof(students)/sizeof(students[0]); i ++){
STUDENT_S *pStu = Student_New(students[i].name, students[i].age);
if(!pStu){
fprintf(stderr, "out of momory");
List_Api_FreeEx(pList, (void(*)(void*))Student_Free);
exit(1);
}
iRet = List_Api_Append(pList, pStu);
if(iRet != LIST_OK){
Student_Free(pStu);
}
pStu = NULL;
}
printf("\ncount: %u\n", List_Api_GetCount(pList));
printf("output from first to last\n");
pstIter = List_Api_Begin(pList);
while(pstIter != NULL){
STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
if(v)
{
printf("Name: %s\n", v->name);
printf("Age: %d\n", v->age);
}
pstIter = List_Api_Next(pstIter);
}
printf("\noutput from last to first\n");
pstIter = List_Api_Last(pList);
while(pstIter != NULL){
STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
if(v)
{
printf("Name: %s\n", v->name);
printf("Age: %d\n", v->age);
}
pstIter = List_Api_Previous(pstIter);
}
printf("\nDelete first student\n");
pstIter = List_Api_Begin(pList);
//pstIter = List_Api_Next(pstIter); //如果要刪除中間的一個,將這一句前面的註釋去掉
(void)List_Api_Delete(pList, pstIter);
Student_Free((STUDENT_S*)(pstIter->data));
printf("\nnow count: %u\n", List_Api_GetCount(pList));
printf("left students are:\n");
pstIter = List_Api_Begin(pList);
while(pstIter != NULL){
STUDENT_S *v = (STUDENT_S *)List_Api_GetData(pstIter);
if(v)
{
printf("Name: %s\n", v->name);
printf("Age: %d\n", v->age);
}
pstIter = List_Api_Next(pstIter);
}
List_Api_FreeEx(pList, (void(*)(void*))Student_Free);
return 0;
}