下面代码是数据结构双链表以及双链表的基本操作,和对双链表进行二次封装实现堆栈
函数封装
-
doulist.h
#ifndef DOULIST_H__ #define DOULIST_H__ //双链表 typedef struct list_st { struct list_st *prev; void *data; struct list_st *next; }list_t; #define HEADINSERT 1 #define TAILINSERT 2 //创建链表 list_t *list_create(void); //插入数据 int list_insert(list_t *head,const void *data,int size,int mode); //显示链表数据 int list_display(const list_t *head,void (*print_data)(void *)); //取数据 int list_feach_data(list_t *head,const void *data,int size,void *redata); //删除数据 int list_delete_data(list_t *head,const void *data,int size); //头结点 void *list_first(list_t *head); //尾节点 void *list_last(list_t *head); //销毁链表 int list_destroy(list_t *head); #endif
-
doulist.c
#include <stdlib.h> #include <string.h> #include "doulist.h" list_t *list_create(void) { list_t *head = NULL; head = malloc(sizeof(*head)); if(head == NULL) return NULL; head->prev = head; head->next = head; head->data = NULL; return head; } int list_insert(list_t *head,const void *data,int size,int mode) { list_t *new = NULL; if(head == NULL || data == NULL || (mode != 1 && mode != 2)\ || size <= 0) return -1; new = malloc(sizeof(*new)); if(new == NULL) return -2; new->data = malloc(size); if(new->data == NULL) { free(new); return -3; } memcpy(new->data,data,size); switch(mode) { case HEADINSERT: new->next = head->next; new->prev = head; head->next = new; new->next->prev = new; break; case TAILINSERT: new->next = head; new->prev = head->prev; head->prev = new; new->prev->next = new; break; } return 0; } int list_display(const list_t *head,void (*print_data)(void *)) { list_t *pos = NULL; if(head == NULL) return -1; for(pos = head->next; pos != head; pos=pos->next) { //printf("",pos->data); print_data(pos->data); } return 0; } int list_destroy(list_t *head) { list_t *pos = NULL,*last = NULL; if(head == NULL) return -1; last = head->prev; for(pos = head->next; pos != head; pos = pos->next) { if(pos->prev->data != NULL) free(pos->prev->data); free(pos->prev); } free(last->data); free(last); return 0; } int list_feach_data(list_t *head,const void *data,int size,void *redata) { list_t *pos = NULL; if(head == NULL || data == NULL || size <= 0) return -1; for(pos = head->next; pos != head; pos = pos->next) { if(memcmp(pos->data,data,size) == 0) { if(redata != NULL) memcpy(redata,pos->data,size); free(pos->data); pos->prev->next = pos->next; pos->next->prev = pos->prev; free(pos); return 0; } } return -2; } int list_delete_data(list_t *head,const void *data,int size) { return list_feach_data(head,data,size,NULL); /* list_t *pos = NULL; if(head == NULL || data == NULL || size <= 0) return -1; for(pos = head->next; pos != head; pos = pos->next) { if(memcmp(pos->data,data,size) == 0) { free(pos->data); pos->prev->next = pos->next; pos->next->prev = pos->prev; free(pos); return 0; } } return -2; */ } void *list_first(list_t *head) { if(head == NULL) return NULL; return head->next->data; } void *list_last(list_t *head) { if(head == NULL) return NULL; return head->prev->data; }
-
stack.h
#ifndef STACK_H__ #define STACK_H__ typedef void stack_t; stack_t *stack_create(void); int stack_push(stack_t *stack,const void *data,int size); int stack_pop(stack_t *stack,void *redata,int size); int stack_destroy(stack_t *stack); #endif
-
stack.c
#include "stack.h" #include "doulist.h" stack_t *stack_create(void) { return list_create(); } int stack_push(stack_t *stack,const void *data,int size) { return list_insert((list_t *)stack,data,size,HEADINSERT); } int stack_pop(stack_t *stack,void *redata,int size) { return list_feach_data((list_t *)stack,list_first((list_t *)stack),size,redata); } int stack_destroy(stack_t *stack) { return list_destroy((list_t *)stack); }
函数库的制作
-
静态库制作
把.c文件编译成.o文件
gcc -c doulist.c -o doulist.o gcc -c stack.c -o stack.o
编译库
ar crs -o libtest.a doulist.o stack.o //ar crs lib库名.a *.o
使用库
gcc main.c -L ./ -ltest //gcc main.c -L 库文件位置 -l库名
-
动态库制作
制作库gcc doulist.c stack.c -fPIC -shared -o libtest.so
配置库
(1)将libtest.so放到/usr/lib或/lib目录下
(2)通过export LD_LIBRARY_PATH=/home/linux/ych/lib 将库所在的绝对路径添加至环境变量中(通过echo $LD_LIBRARY_PATH查看此环境变量的值;通过unset LD_LIBRARY_PATH来删除此环境变量里的值)
(3)在/etc/ld.so.conf.d/下新建一个sudo vi test.conf文件,在里面写入库所在的绝对路径,第三条亲测
更新配置sudo ldconfig
使用库
gcc main.c -L ../ -ltest gcc main.c -L 库文件位置 -l库名
-
静态库和动态库的优劣
引用至 https://blog.csdn.net/fhb1922702569/article/details/53585172
1 静态链接库的优点
(1) 代码装载速度快,执行速度略比动态链接库快;
(2) 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。
2 动态链接库的优点
(1) 更加节省内存并减少页面交换;
(2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;
(3) 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
(4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。
3 不足之处
(1) 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;
(2) 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。