堆棧是一種先進後出的數據結構。是一種只容許在其一端進行插入或者刪除的線性表。容許插入或刪除操做的一端爲棧頂,另外一端稱爲棧底。對堆棧的插入和刪除操做稱爲入棧和出棧。數據結構
OpenSSL大量採用堆棧來存放數據。它實現了一個通用的堆棧,能夠方便的存儲任意數據。它實現了許多基本的堆棧操做,主要有:堆棧拷貝(sk_dup)、構建新堆棧(sk_new_null,sk_new)、插入數據(sk_insert)、刪除數據(sk_delete)、查找數據(sk_find,sk_find_ex)、入棧(sk_push)、出棧(sk_pop)、獲取堆棧元素個數(sk_num)、獲取堆棧值(sk_value)、設置堆棧值(sk_set)和堆棧排序(sk_sort)。函數
OpenSSL堆棧數據結構在crypto/stack/stack.h中定義,其詳細定義以下:spa
typedef struct stack_st { int num; char **data; int sorted; int num_alloc; int (*comp)(const void *, const void *); } _STACK; /* Use STACK_OF(...) instead */
主要項意義以下:指針
num:int數據類型,堆棧中存放數據的個數。code
data:char **數據類型,用於存放數據地址,每一個數據地址存放在data[0]到data[num-1]中。對象
sorted:int數據類型,該堆棧是否排序,若已經排序,則爲1,不然爲0。堆棧數據通常是無序的,只有當用戶調用了sk_sort操做,其值才爲1。排序
num_alloc:int數據類型,分配內存的次數。接口
comp:回調函數,堆棧內存放數據的比較函數地址,此函數用於排序和查找操做;當用戶生成一個新堆棧時,能夠指定comp爲用戶實現的一個比較函數;或當堆棧已經存在時經過調用sk_set_cmp_func函數來從新指定比較函數。內存
用戶直接調用最底層的堆棧操做函數是一個麻煩的事情,對此openssl提供了用宏來幫助用戶實現接口。用戶能夠參考safestack.h來定義本身的上層堆棧操做函數。openssl堆棧實現源碼位於crypto/stack目錄下。ssl
函數功能:新建一個堆棧對象_STACK。該函數直接調用sk_new函數,參數直接傳的是(int (*)(const void *, const void *))0。
函數定義:
_STACK *sk_new_null(void);
參數說明:
無。
返回值:若堆棧對象_STACK新建成功,則直接返回堆棧對象_STACK的指針。不然返回NULL。
函數功能:根據對象比較函數來建立一個堆棧對象_STACK。該函數首先調用OPENSSL_malloc函數給對象分配內存,而後給每一個對象分配相對應的內存。注意:數據地址首先分配的是4個。
函數定義:
_STACK *sk_new(int (*cmp)(constvoid *, const void *));
參數說明:
cmp:[in]回調函數,對象的比較函數。
返回值:若堆棧對象_STACK新建成功,則直接返回堆棧對象_STACK的指針。不然返回NULL。
函數功能:釋放堆棧本身的內存空間函數。該函數首先調用OPENSSL_free函數釋放掉數據地址,而後再調用OPENSSL_free函數釋放掉堆棧對象自己。
函數定義:
void sk_free(_STACK *st);
參數說明:
st:[in] _STACK *數據類型,須要釋放的堆棧對象。
返回值:無。
函數功能:本函數用於釋放堆棧內存放的數據以及堆棧自己,它須要一個由用戶指定的針對具體數據的釋放函數。若是用戶僅調用sk_free函數,則只會釋放堆棧自己所用的內存,而不會釋放數據內存。
函數定義:
void sk_pop_free(_STACK *st,void (*func)(void *));
參數說明:
st:[in] _STACK *數據類型,須要釋放的堆棧對象。
func:[in]對象的釋放函數。
返回值:無。
函數功能:根據指定的位置往堆棧對象中插入數據。該函數首先判斷堆棧對象是否須要分配內存空間,若須要,則分配內存空間。而後將數據添加到指定的位置。
函數定義:
int sk_insert(_STACK *sk, void *data, int where);
參數說明:
sk:[in] _STACK *數據類型,須要添加數據的堆棧對象。
data:[in] void *數據類型,須要添加的數據。
where:[in] int數據類型,須要插入的位置。
返回值:返回堆棧對象中數據的個數。
函數功能:刪除指定位置的堆棧對象。該函數首先判斷須要刪除數據的位置是否合法,若不合法,則返回。而後循環移位賦值。
函數定義:
void *sk_delete(_STACK *st,int loc);
參數說明:
sk:[in] _STACK *數據類型,須要刪除數據的堆棧對象。
loc:[in] int數據類型,須要刪除的位置。
返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL。
函數功能:從堆棧對象中刪除指定的對象值。該函數首先遍歷整個堆棧對象中的對象值,判斷每一個堆棧對象值是否與須要刪除的對象值相等,若相等,則刪除,並返回值。
函數定義:
void *sk_delete_ptr(_STACK *st,void *p);
參數說明:
sk:[in] _STACK *數據類型,須要刪除數據的堆棧對象。
p:[in] void *數據類型,須要刪除的對象值。
返回值:若堆棧對象中有須要刪除的值,則返回刪除成功後的值;若沒有,則直接返回NULL。
函數功能:根據數據地址來查找它在堆棧中的位置。當堆棧設置了比較函數時,它首先對堆棧進行排序,而後經過二分法進行查找。若是堆棧沒有設置比較函數,它只是簡單的比較數據地址來查找。
函數定義:
int sk_find(_STACK *st,void *data);
參數說明:
sk:[in] _STACK *數據類型,須要查找數據的堆棧對象。
p:[in] void *數據類型,須要查找的對象值。
返回值:若堆棧中有該對象,則返回它的位置,不然返回-1。
函數功能:根據數據地址來查找它在堆棧中的位置。當堆棧設置了比較函數時,它首先對堆棧進行排序,而後經過二分法進行查找。若是堆棧沒有設置比較函數,它只是簡單的比較數據地址來查找。
函數定義:
int sk_find_ex(_STACK *st,void *data);
參數說明:
sk:[in] _STACK *數據類型,須要查找數據的堆棧對象。
p:[in] void *數據類型,須要查找的對象值。
返回值:若堆棧中有該對象,則返回它的位置,不然返回-1。
函數功能:向堆棧棧頂插入數據。該函數實際上調用的是sk_insert函數,最後一個參數傳的是st->num。
函數定義:
int sk_push(_STACK *st,void *data);
參數說明:
sk:[in] _STACK *數據類型,須要添加數據的堆棧對象。
data:[in] void *數據類型,須要添加的數據。
返回值:返回堆棧對象中數據的個數。
函數功能:往堆棧棧底插入一條數據。該函數實際上調用的是sk_insert函數,最後一個參數傳的是0。
函數定義:
int sk_unshift(_STACK *st,void *data);
參數說明:
sk:[in] _STACK *數據類型,須要添加數據的堆棧對象。
data:[in] void *數據類型,須要添加的數據。
返回值:返回堆棧對象中數據的個數。
函數功能:刪除棧底的數據。該函數實際上調用的是sk_delete函數,第二個參數傳的是0。
函數定義:
void *sk_shift(_STACK *st);
參數說明:
sk:[in] _STACK *數據類型,須要刪除數據的堆棧對象。
返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL。
函數功能:刪除棧頂的數據。該函數實際上調用的是sk_delete函數,第二個參數傳的是st->num - 1。
函數定義:
void *sk_shift(_STACK *st);
參數說明:
sk:[in] _STACK *數據類型,須要刪除數據的堆棧對象。
返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL。
函數功能:初始化堆棧對象的數據值。該函數直接調用memset函數來初始化堆棧對象的數據值。
函數定義:
void sk_zero(_STACK *st);
參數說明:
sk:[in] _STACK *數據類型,須要初始化的堆棧對象。
返回值:無。
函數功能:設置堆棧存放數據的比較函數。因爲堆棧不知道用戶存放的是什麼數據,因此,比較函數必須由用戶本身實現。
函數定義:
int (*sk_set_cmp_func(_STACK *sk,int (*c)(const void *, const void *))) (const void *, const void *);
參數說明:
sk:[in] _STACK *數據類型,須要設置比較函數的堆棧對象。
c:比較函數。
返回值:若設置成功,則返回比較函數。不然返回原來的比較函數。
函數功能:複製一個堆棧對象。該函數首先聲明一個堆棧對象,而後將須要複製的堆棧對象逐個賦值。
函數定義:
_STACK *sk_dup(_STACK *st);
參數說明:
sk:[in] _STACK *數據類型,須要複製的堆棧對象。
返回值:若複製成功,則返回堆棧對象指針,不然返回NULL。
函數功能:對堆棧中的數據進行排序。它首先根據sorted來判斷是否已經排序,若是未排序則調用了標準C函數qsort進行快速排序。
函數定義:
void sk_sort(_STACK *st);
參數說明:
sk:[in] _STACK *數據類型,須要排序的堆棧對象。
返回值:無。
函數功能:獲取堆棧對象中的排序標識。
函數定義:
int sk_is_sorted(const _STACK *st);
參數說明:
sk:[in] const _STACK *數據類型,須要獲取值的堆棧對象。
返回值:堆棧對象排序標識。
函數功能:獲取堆棧對象中的數據的總數。
函數定義:
int sk_num(const _STACK *st );
參數說明:
sk:[in] const _STACK *數據類型,須要獲取值的堆棧對象。
返回值:堆棧對象中的數據的總數。
函數功能:獲取指定位置的堆棧對象中的數據。
函數定義:
void *sk_value(const _STACK *st,int i);
參數說明:
sk:[in] const _STACK *數據類型,須要獲取值的堆棧對象。
i:[in] int數據類型,指定位置。
返回值:堆棧對象中的數據值指針。
本實例中,首先聲明一個people_info_st對象,而後利用宏定義來操做底層的堆棧處理函數。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/safestack.h> #include <openssl/crypto.h> #define sk_PEOPLE_INFO_new(cmp) SKM_sk_new(PEOPLE_INFO, (cmp)) #define sk_PEOPLE_INFO_new_null() SKM_sk_new_null(PEOPLE_INFO) #define sk_PEOPLE_INFO_free(st) SKM_sk_free(PEOPLE_INFO, (st)) #define sk_PEOPLE_INFO_num(st) SKM_sk_num(PEOPLE_INFO, (st)) #define sk_PEOPLE_INFO_value(st, i) SKM_sk_value(PEOPLE_INFO, (st), (i)) #define sk_PEOPLE_INFO_set(st, i, val) SKM_sk_set(PEOPLE_INFO, (st), (i), (val)) #define sk_PEOPLE_INFO_zero(st) SKM_sk_zero(PEOPLE_INFO, (st)) #define sk_PEOPLE_INFO_push(st, val) SKM_sk_push(PEOPLE_INFO, (st), (val)) #define sk_PEOPLE_INFO_unshift(st, val) SKM_sk_unshift(PEOPLE_INFO, (st), (val)) #define sk_PEOPLE_INFO_find(st, val) SKM_sk_find(PEOPLE_INFO, (st), (val)) #define sk_PEOPLE_INFO_delete(st, i) SKM_sk_delete(PEOPLE_INFO, (st), (i)) #define sk_PEOPLE_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PEOPLE_INFO, (st), (ptr)) #define sk_PEOPLE_INFO_insert(st, val, i) SKM_sk_insert(PEOPLE_INFO, (st), (val), (i)) #define sk_PEOPLE_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PEOPLE_INFO, (st), (cmp)) #define sk_PEOPLE_INFO_dup(st) SKM_sk_dup(PEOPLE_INFO, st) #define sk_PEOPLE_INFO_pop_free(st, free_func) SKM_sk_pop_free(PEOPLE_INFO, (st), (free_func)) #define sk_PEOPLE_INFO_shift(st) SKM_sk_shift(PEOPLE_INFO, (st)) #define sk_PEOPLE_INFO_pop(st) SKM_sk_pop(PEOPLE_INFO, (st)) #define sk_PEOPLE_INFO_sort(st) SKM_sk_sort(PEOPLE_INFO, (st)) typedef struct people_info_st { char *name, *otherInfo; int age; }PEOPLE_INFO; PEOPLE_INFO *PEOPLE_INFO_Malloc() { PEOPLE_INFO *a= ( PEOPLE_INFO * )OPENSSL_malloc(sizeof(PEOPLE_INFO)); a->name = ( char * )OPENSSL_malloc(20); strcpy( a->name, "zcp" ); a->otherInfo = ( char * )OPENSSL_malloc(20); strcpy( a->otherInfo, "no info" ); a->age = 20; return a; } void PEOPLE_INFO_Free( PEOPLE_INFO *a ) { OPENSSL_free( a->name ); OPENSSL_free( a->otherInfo ); OPENSSL_free( a ); } static int PEOPLE_INFO_cmp( const PEOPLE_INFO *const *a, const PEOPLE_INFO *const *b ) { int ret; /* 只比較關鍵字 */ ret = strcmp( (*a)->name, (*b)->name ); return ret; } int main( int argc, char *argv[] ) { STACK_OF(PEOPLE_INFO) *s,*snew; PEOPLE_INFO *s1,*one,*s2; int i, num; /* 新建一個堆棧對象 */ s = sk_PEOPLE_INFO_new_null(); /* 新建一個堆棧對象 */ snew = sk_PEOPLE_INFO_new( PEOPLE_INFO_cmp ); s2 = PEOPLE_INFO_Malloc(); sk_PEOPLE_INFO_push( snew, s2 ); i=sk_PEOPLE_INFO_find( snew, s2 ); s1 = PEOPLE_INFO_Malloc(); sk_PEOPLE_INFO_push( s, s1 ); num = sk_PEOPLE_INFO_num( s ); for( i = 0;i< num; i++ ) { printf("堆棧s中的數據有:\n" ); one = sk_PEOPLE_INFO_value( s, i ); printf("PEOPLE_INFO name : %s\n",one->name ); printf("PEOPLE_INFO age : %d\n",one->age ); printf("PEOPLE_INFO otherinfo : %s\n\n\n",one->otherInfo ); printf("\n\n"); } for( i = 0;i< num; i++ ) { printf("堆棧snew中的數據有:\n" ); one = sk_PEOPLE_INFO_value( snew, i ); printf("PEOPLE_INFO name : %s\n",one->name ); printf("PEOPLE_INFO age : %d\n",one->age ); printf("PEOPLE_INFO otherinfo : %s\n\n\n",one->otherInfo ); printf("\n\n"); } sk_PEOPLE_INFO_pop_free( s, PEOPLE_INFO_Free ); sk_PEOPLE_INFO_pop_free( snew, PEOPLE_INFO_Free ); return 0; }