函数封装和函数库的制作

下面代码是数据结构双链表以及双链表的基本操作,和对双链表进行二次封装实现堆栈

函数封装

  • 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 
     #include 
     
     #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中很常见。

你可能感兴趣的:(函数库制作,函数封装,数据结构,动态库,静态库,数据结构)