IPMI经验教训(C内存泄露教训)

来源:互联网 发布:淘宝的隐私设置在哪里 编辑:程序博客网 时间:2024/05/23 21:05
一个由c/C++编译的程序占用的内存分为以下几个部分栈区(stack)―  由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 堆区(heap) ―  一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 全局区(静态区)(static)―,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 文字常量区  ―常量字符串就是放在这里的。 程序结束后由系统释放 程序代码区―存放函数体的二进制代码。

 

1.      Malloc() 的空间必须用free()函数进行释放,否则会发生内存泄露

如:

fun()
{
int a[10];
....
}

fun()
{
int *a;
a = (int *)malloc(10 * sizeof(int));
...}
问:

  是不是第2种方式开辟的空间在函数结束后如果不free  这个空间不释放? 第1种方式在函数结束后会释放空间?

答:

 第二种是在堆上分配的空间,在函数结束后不会释放,需要手动free,程序结束时也会释放.第一种是在栈上分配的,函数结束会自动回收资源

 

2.      用来接收内部函数返回的字符串,字符串长度较确定的可以直接使用字符数组,数组的长度最好用定义的宏,方便以后的修改和维护。

如:

TCHAR  *lpwszStr=NULL; //Pointer to a buffer that receives the translated string

TCHAR  lpwszStr[CMD_LINE_LEN]={0};/ /Pointer to a buffer that receives the translatedstring

3.      被调函数中申请的局部变量、数组的空间在被调函数返回结束时会被释放掉,用调用函数的传进来的指针去指向这段空间是错误的。

如:

 

intsdk_get_online_mac(char* ip_online,char*ipmi_user,char* ipmi_pass,char **Online_mac)

{

char *szBuffer[10];//a buffer that receives the return string

for(i=0;i<10;i++)

{

                   szBuffer[i]=(char*)malloc(szBuffer_length);

                   if (NULL == szBuffer[i])

                   {

                            //(应考虑到本次申请失败,把本次之前申请的空间释放掉)

                            returnIPMI_SDK_MALLOC_ERR;

                   }

                   memset(szBuffer[i],0,szBuffer_length);

}

                    *Online_mac=szbuff[i];//(可以,malloc的空间一直都在,除非手动释放或程序)结束)

}

char szBuffer[PIPE_STR_FREQUENCY][PIPE_STR_LEN]={0};//a buffer receives thereturn string

*Online_mac=szbuff[i];//(不可以,数组空间在栈区,函数结束会释放空间,会使*Online_mac指向非法空间,解决办法如下:

intsdk_get_online_mac(char* ip_online,char*ipmi_user,char* ipmi_pass,char *Online_mac)

{

char szBuffer[PIPE_STR_FREQUENCY][PIPE_STR_LEN]={0};//a buffer receives thereturn string

memcpy(Online_mac, zBuffer [3],IPMI_STR_LEN);//把字符串拷贝到Online_mac指向的空间

}

总结:

传参类型Char **buf,一般用于需在被调函数中申请空间的函数。

 

4.      定义的变量、指针、数组等要进行初始化。

5.      要考虑到程序可能执行错误的情况,返回规范的错误码。

6.      为方便程序的调试,应加上一些规范的打印信息

如:

           printf("%s, line:%d,matchfail!\n", __FUNCTION__, __LINE__);//加上函数名、行号等

         __FUNCTION__、__LINE__:C编译器提供的预定义宏。

7.      代码要及时的测试其正确性、实用性。

8.      主动让别人检查自己代码的规范性,有无错误、漏洞。

9.      C的应用,注意字符串操作函数的应用

如:strcpy();拷贝时注意拷贝的字符串长度最大为空间长度-1,为‘\0’,留出空间

10

typedef int(*fun_sdk_getAuthedDeviceList)(char* ipmiUser, char* ipmiPass,

         char*startIP, char* endIP, char* mask, DataList** res);//定义函数指针类型

intsdk_getAuthedDeviceList_stub(char*ipmiUser, char* ipmiPass,

         char*start_ip, char* end_ip, char* mask, DataList** res, int* result)

{

         fun_sdk_getAuthedDeviceListfun = NULL;//用定义的函数类型,定义函数指针变量

         char*funName = IPMI_SDK_FUN_NAME_AUTHED_DEV_LIST;

 

         fun= (fun_sdk_getAuthedDeviceList)GetProcAddress(ipmi.hsdkDLL, funName);

         if(NULL != fun)

         {

                   *result= fun(ipmiUser, ipmiPass, start_ip, end_ip, mask, res);

                   returnIPMI_SRV_OK;

         }

         else

         {

                   DBG("%s_stub(0x%x):sdk(%s) is NULL", funName, IPMI_SRV_GET_SDK_FUNCTION_ERR, funName);

                   returnIPMI_SRV_GET_SDK_FUNCTION_ERR;

         }

}

0 0
原创粉丝点击