在开发过程中,经常会遇到想要申请的内存长度不固定的情况,在一般效率不高时,直接使用malloc或者free就可以,但是在一些效率要求较高的场合,频繁的使用malloc和free会严重影响到系统的性能。在大多数情况下,我们遇到的情况都是:申请的长度一般都在某个值之下,特殊情况下,会出现长度大于此值;这时候如果使用一个定长的数组,则可以显著提升系统效率,但是又照顾不了个别情况下数组无法装下的问题,并且长度不太好确定,太长会浪费空间,太短又可能不够用;如果使用malloc动态申请内存,虽然能够满足各种长度要求,但是会对效率产生显著的影响;如何兼顾效率和空间浪费是个两难的问题。
下面的这段代码可以自动在栈和堆之间进行切换,使用时只需要根据经验值设定一个固定大小,经验值之内的内存自动在栈上定义,大于经验值的内存都在堆上分配,它实现的原理是:在结构体内部定义一个定长数组和一个指针,如果用户需要的长度小于数组长度,则直接使用数组,无需在堆上申请内存,如果用户使用过程中,需要的长度增加了,并且超过了定长数组,则自动在堆上申请内存,并将数据从数组中转移过来,定长数组的长度为宏DEFAULT_BUF_LEN,可根据自己的经验值进行修改,上述的这些过程对使用着来说是透明的。这段代码包括了实现代码,以及一个简单的使用及测试用例;
下面的代码提供了6个接口函数,其名称和功能为:
1、bool Smart_Buf_Init(struct Smart_Buffer* smartBuf, int len);它主要完成对结构体struct Smart_Buffer的初始化工作,并可指定长度,如果指定长度小于宏DEFAULT_BUF_LEN,则指定长度不被采用;
2、void Smart_Buf_Uninit(struct Smart_Buffer* smartBuf);主要对结构体struct Smart_Buffer的反初始化工作,如果内部有从堆中申请了内存,则在该函数内部会进行释放;
3、bool Smart_Buf_SetData(struct Smart_Buffer* smartBuf, char* dataBuf);该接口主要完成存储一个buf的功能;
4、bool Smart_Buf_StrCat(struct Smart_Buffer* smartBuf, char* dataBuf);该接口主要将dataBuf中的内容拼接到smartBuf中;
5、char* Smart_Buf_GetBuf(struct Smart_Buffer* smartBuf);该接口可以获取smartBuf中正在使用的内存的地址,如果使用的是定长数组,则返回数组的首地址,如果是从堆中新申请的内存,则返回该内存的地址。
6、void Smart_Buf_description(struct Smart_Buffer* smartBuf);该接口函数可以打印smartBuf中的内部情况;
需要注意的是:
1、使用之前一定要先调用初始化接口:使用结束一定要调用反初始化接口
2、使用过程中尽量使用接口函数对内存进行操作,而不是直接操纵结构体内的内存。
/*******************************************Smart_Buffer*****************************************************
*说明:
*功能:
*接口函数说明:
*使用示例:
*注意:
* 开始使用时需调用:Smart_Buf_Init
* 使用结束需要调用:Smart_Buf_Uninit
*******************************************Smart_Buffer*****************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define DEFAULT_BUF_LEN 1024
#ifndef bool
#define bool char
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
struct Smart_Buffer{
bool bUseHeap;
char* buf;
char array[DEFAULT_BUF_LEN];
int capacity;
int used_len;
};
bool Smart_Buf_Init(struct Smart_Buffer* smartBuf, int len);
bool Smart_Buf_SetData(struct Smart_Buffer* smartBuf, char* dataBuf);
bool Smart_Buf_StrCat(struct Smart_Buffer* smartBuf, char* dataBuf);
void Smart_Buf_Uninit(struct Smart_Buffer* smartBuf);
static bool _Smart_Buf_AddBuf(struct Smart_Buffer* smartBuf,int len);
void Smart_Buf_description(struct Smart_Buffer* smartBuf);
char* Smart_Buf_GetBuf(struct Smart_Buffer* smartBuf);
bool Smart_Buf_Init(struct Smart_Buffer* smartBuf,int len)
{
if(NULL == smartBuf)
return false;
smartBuf->buf = NULL;
if(len < DEFAULT_BUF_LEN){//Request buffer length is less than default length,will usearray
smartBuf->capacity = DEFAULT_BUF_LEN;
smartBuf->bUseHeap = false;
memset(smartBuf->array, '\0', smartBuf->capacity);
}else{ // Request buffer length is longer than default length,will malloc memory;
smartBuf->capacity = len + DEFAULT_BUF_LEN;
smartBuf->buf = malloc(smartBuf->capacity);
if(NULL == smartBuf->buf)
return false;
smartBuf->bUseHeap = true;
memset(smartBuf->buf, '\0', smartBuf->capacity);
}
smartBuf->used_len = 0;
return true;
}
static bool _Smart_Buf_AddBuf(struct Smart_Buffer* smartBuf,int len)
{
if(NULL == smartBuf || len <= 0)
return false;
if(smartBuf->capacity >= len)
return true;
int new_len = len + DEFAULT_BUF_LEN;
if(smartBuf->bUseHeap){
smartBuf->buf = realloc(smartBuf->buf, new_len * sizeof(char));
}else{
smartBuf->buf = malloc(new_len* sizeof(char));
memset(smartBuf->buf, '\0',new_len * sizeof(char));
strncpy(smartBuf->buf,smartBuf->array,smartBuf->used_len);
memset(smartBuf->array, '\0',DEFAULT_BUF_LEN);
smartBuf->bUseHeap = true;
}
smartBuf->capacity = new_len;
return true;
}
bool Smart_Buf_SetData(struct Smart_Buffer* smartBuf, char* dataBuf)
{
if(NULL == smartBuf)
return false;
if(NULL == dataBuf)
return true;
if(smartBuf->capacity < strlen(dataBuf)){//capacity of smartBuf is less than the lenght of dataBuf,will malloc
if(!_Smart_Buf_AddBuf(smartBuf,strlen(dataBuf) + DEFAULT_BUF_LEN))
return false;
}
if(smartBuf->bUseHeap){//use buffer
sprintf(smartBuf->buf,"%s",dataBuf);
smartBuf->used_len = strlen(smartBuf->buf);
}else{//use array
sprintf(smartBuf->array,"%s",dataBuf);
smartBuf->used_len = strlen(smartBuf->array);
}
return true;
}
bool Smart_Buf_StrCat(struct Smart_Buffer* smartBuf, char* dataBuf)
{
if(NULL == smartBuf)
return false;
if(NULL == dataBuf)
return true;
int new_len = 0;
if(smartBuf->capacity < strlen(dataBuf)+ smartBuf->used_len){
if(!_Smart_Buf_AddBuf(smartBuf,strlen(dataBuf)+ smartBuf->used_len))
return false;
}
if(smartBuf->bUseHeap){
strcat(smartBuf->buf,dataBuf);
smartBuf->used_len = strlen(smartBuf->buf);
}else{
strcat(smartBuf->array,dataBuf);
smartBuf->used_len = strlen(smartBuf->array);
}
return true;
}
void Smart_Buf_Uninit(struct Smart_Buffer* smartBuf)
{
if(NULL == smartBuf)
return ;
if(smartBuf->bUseHeap && NULL != smartBuf->buf)
free(smartBuf->buf);
smartBuf->bUseHeap = false;
smartBuf->buf = NULL;
smartBuf->capacity = DEFAULT_BUF_LEN;
}
char* Smart_Buf_GetBuf(struct Smart_Buffer* smartBuf)
{
if(NULL == smartBuf)
return NULL;
return smartBuf->bUseHeap ? smartBuf->buf : smartBuf->array;
}
void Smart_Buf_description(struct Smart_Buffer* smartBuf)
{
if(NULL == smartBuf)
return ;
printf("\n|---------- description of struct Smart_Buffer:----------| \n");
printf(" smartBuf address : [%p]\n",smartBuf);
printf(" Is use heap : [%s]\n",smartBuf->bUseHeap ? "Yes" : "No");
printf(" capacity : [%d]\n",smartBuf->capacity);
printf(" used length : [%d]\n",smartBuf->used_len);
printf(" - array address : [%p]\n",smartBuf->array);
printf(" - array content : [%s]\n",smartBuf->array);
printf(" - buffer address : [%p]\n",smartBuf->buf);
printf(" - buffer content : [%s]\n\n",smartBuf->buf ? smartBuf->buf : "NULL");
}
/*----------------------test------------------------------*/
void test1()
{
printf("\n------------into function:test1()\n");
struct Smart_Buffer mySmartBuf;
printf("\n will init buffer length 5 (default length is 10)\n");
if(!Smart_Buf_Init(&mySmartBuf,5)){
printf("fail from function:Smart_Buf_Init\n");
return ;
}
printf("\n after Smart_Buf_Init():\n");
Smart_Buf_description(&mySmartBuf);
printf("\n will set data:[hello ]\n");
if(!Smart_Buf_SetData(&mySmartBuf,"hello ")){
printf("fail from function:Smart_Buf_SetData\n");
return ;
}
printf("\n after Smart_Buf_SetData():\n");
Smart_Buf_description(&mySmartBuf);
printf("***test-Smart_Buf_GetBuf -content:[%s]***\n",Smart_Buf_GetBuf(&mySmartBuf));
printf("\n will call Smart_Buf_StrCat with:[this is jason!]\n");
if(!Smart_Buf_StrCat(&mySmartBuf, " this is jason! ")){
printf("fail from function:Smart_Buf_StrCat\n");
return ;
}
printf("\n after Smart_Buf_StrCat():\n");
Smart_Buf_description(&mySmartBuf);
printf("***test-Smart_Buf_GetBuf -content:[%s]***\n",Smart_Buf_GetBuf(&mySmartBuf));
printf("\n will unit buffer...\n");
Smart_Buf_Uninit(&mySmartBuf);
printf("\n after Smart_Buf_Uninit():\n");
Smart_Buf_description(&mySmartBuf);
}
/*----------------------------------------------------*/
void test2()
{
printf("\n------------into function:test2()\n");
struct Smart_Buffer mySmartBuf;
printf("\n will init buffer length 20(default length is 10)\n");
if(!Smart_Buf_Init(&mySmartBuf,20)){
printf("fail from function:Smart_Buf_Init\n");
return ;
}
printf("\n after Smart_Buf_Init():\n");
Smart_Buf_description(&mySmartBuf);
printf("\n will set data:[hello, this jason, and i am from XI'AN,china..................... ]\n");
if(!Smart_Buf_SetData(&mySmartBuf,"hello, this jason, and i am from XI'AN,china..................... ")){
printf("fail from function:Smart_Buf_SetData\n");
return ;
}
printf("\n after Smart_Buf_SetData():\n");
Smart_Buf_description(&mySmartBuf);
printf("***test-Smart_Buf_GetBuf -content:[%s]***\n",Smart_Buf_GetBuf(&mySmartBuf));
printf("\n will call Smart_Buf_StrCat with:[ <><><><><><><><><><><><><><><><><><><><><><><><><><><><><>] \n");
if(!Smart_Buf_StrCat(&mySmartBuf, " <><><><><><><><><><><><><><><><><><><><><><><><><><><><><>")){
printf("fail from function:Smart_Buf_StrCat\n");
return ;
}
printf("\n after Smart_Buf_StrCat():\n");
Smart_Buf_description(&mySmartBuf);
printf("\n will unit buffer...\n");
printf("***test-Smart_Buf_GetBuf -content:[%s]***\n",Smart_Buf_GetBuf(&mySmartBuf));
Smart_Buf_Uninit(&mySmartBuf);
printf("\n after Smart_Buf_Uninit():\n");
Smart_Buf_description(&mySmartBuf);
}
int main()
{
test1();
test2();
return 0;
}