opensll中实现了很多的数据结构,借学习openssl源码来复习数据结构。源码在crypto\stack中。先来分析一下其中实现的源码中结构体定义和一些函数。参考了赵春平老师的Openssl编程
typedef struct stack_st
{
int num;//存在的节点数
char **data;//由于不知道要存储数据的类型,存放数据的地址。类似C++的模板的功能
int sorted;//是否有序
int num_alloc;//申请的节点数
int (*comp)(const char * const *, const char * const *); //函数指针,存储类型的比较函数
} STACK;
我对源码的部分进行一点修改,主要把OPENSSL_realloc,OBJ_bsearch_ex等函数改成C标准库中函数,这样可以没安装openssl的情况下,测试代码。下面是几个主要函数。
/********************************************************
*函数功能:创建一个stack,并初始化
*函数参数:要存储类型的比较函数
*函数返回值:成功,则返回创建的STACK对象,失败则返回NULL
*******************************************************/
STACK *sk_new(int (*c)(const char * const *, const char * const *))
{
STACK *ret;
int i;
if ((ret=(STACK *)malloc(sizeof(STACK))) == NULL)
goto err;
//data相当于是一个指针数据,数组的每个成员是一个指向char*的指针
if ((ret->data=(char **)malloc(sizeof(char *)*MIN_NODES)) == NULL)
goto err;
for (i=0; i<MIN_NODES; i++)
ret->data[i]=NULL;
ret->comp=c;
ret->num_alloc=MIN_NODES;
ret->num=0;
ret->sorted=0;
return(ret);
err:
if(ret)
free(ret);
return(NULL);
}
/********************************************************
*函数功能:创建一个stack,并初始化
*函数参数:st即要操作的栈;data即为要插入数据的地址;loc即要插入的位置
*函数返回值:成功,则返回节点数目,失败则返回0
*******************************************************/
int sk_insert(STACK *st, char *data, int loc)
{
char **s;
if(st == NULL) return 0;
if (st->num_alloc <= st->num+1)//首先判断已经申请的节点数是否小于已经存在的节点数+1,是,则扩大2倍,realloc
{//注意realloc函数,申请的空间要大于原来的空间,否则数据丢失。申请成功则释放之前的空间,返回成功的内存地址
s=(char **)realloc((char *)st->data,
(unsigned int)sizeof(char *)*st->num_alloc*2);
if (s == NULL)
return(0);
st->data=s;
st->num_alloc*=2;
}
if ((loc >= (int)st->num) || (loc < 0))
st->data[st->num]=data;
else
{
int i;
char **f,**t;
//相当于把data的数据从loc开始向后移动一个位置,空出loc位置,具体功能同#ifdef undef 和#endif中的memmove操作
f=(char **)st->data;
t=(char **)&(st->data[1]);
for (i=st->num; i>=loc; i--)
t[i]=f[i];
#ifdef undef /* no memmove on sunos :-( */
memmove( (char *)&(st->data[loc+1]),
(char *)&(st->data[loc]),
sizeof(char *)*(st->num-loc));
#endif
st->data[loc]=data;//将地址插入
}
st->num++;//节点数加1
st->sorted=0;
return(st->num);
}
/*
函数功能:删除p所指向的内容
*/
char *sk_delete_ptr(STACK *st, char *p)
{
int i;
for (i=0; i<st->num; i++)//线性查找
if (st->data[i] == p)
return(sk_delete(st,i));
return(NULL);
}
下面是测试函数的main函数:
#include <stdio.h>
#include "stack.h"
#include <stdlib.h>
#include <string.h>
typedef struct Student_st
{
char *name;
int age;
char *otherInfo;
}Student;
Student *Student_Malloc()
{
Student *a=(Student*)malloc(sizeof(Student));
a->name=(char*)malloc(20);
strcpy(a->name,"zcp");
a->otherInfo=(char *)malloc(20);
strcpy(a->otherInfo,"no info");
return a;
}
void Student_Free(Student *a)
{
free(a->name);
free(a->otherInfo);
free(a);
}
static int Student_cmp(Student *a,Student *b)
{
int ret;
ret=strcmp(*(char**)a->name,*(char**)b->name);
return ret;
}
int main()
{
STACK *snew;
Student *s1,*one;
int i,num;
snew=sk_new((int(*)(const char *const * ,const char *const * ))Student_cmp);
s1=Student_Malloc();
s1->age=20;
strcpy(s1->name,"xxx");
strcpy(s1->otherInfo,"nickname");
sk_push(snew,(char *)s1);
s1=Student_Malloc();
s1->age=22;
strcpy(s1->name,"bbbu");
strcpy(s1->otherInfo,"nickname");
sk_push(snew,(char *)s1);
s1=Student_Malloc();
s1->age=24;
strcpy(s1->name,"jack");
strcpy(s1->otherInfo,"nickname");
sk_push(snew,(char *)s1);
s1=Student_Malloc();
s1->age=22;
strcpy(s1->name,"tom");
strcpy(s1->otherInfo,"nickname");
sk_push(snew,(char *)s1);
printf("Before FInd*********************************\n");
num=sk_num(snew);
for(i=0;i<num;i++)
{
one=(Student*)sk_value(snew,i);
printf("student name : %s\n",one->name);
printf("sutdent age : %d\n",one->age);
printf("student otherinfo : %s\n\n\n",one->otherInfo);
}
i=sk_find(snew,(char*)s1);
printf("\n\ni=%d",i);
printf("After FInd*********************************\n");
num=sk_num(snew);
for(i=0;i<num;i++)
{
one=(Student*)sk_value(snew,i);
printf("student name : %s\n",one->name);
printf("sutdent age : %d\n",one->age);
printf("student otherinfo : %s\n\n\n",one->otherInfo);
}
sk_pop_free(snew,(void(*)(void*))Student_Free);
return 0;
}
发现一个问题,如果查找,则破坏了之前的栈结构。不知道这样实现的用处。