结合本人在实际项目中所积累的经验,以及曾经犯过的错误,堆内存操作类函数做一个简单的剖析,抛砖引玉,欢迎大家吐槽。
首先,讲一下内存使用异常发生的几种场景。
1、野指针的使用,使用已经释放的指针,如果向野指针中写内容,就极有可能导致设备重启或任务挂死。因为,正在运行的任务的地址被意外的改写。
【避免策略】函数入参要判空,指针使用(包括释放)之前一定要释放。
2、内存函数的错误使用:
void *memset(void *s, int ch, size_t n);
c语言中在<memory.h>或<string.h>,c++中是在<cstring>。作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
【异常情况】如果n的长度 大于指针 s的长度,则会出现内存操作越界现象,同样可能导致设备重启或任务挂死。
【避免策略】确保n 的长度 小于等于 指针s 指向内存的长度。
3、内存拷贝的函数 memcpy:由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。
void *memcpy(void *dest,const void *src, int n);c语言中在<memory.h>或<string.h>,c++中是在<cstring>。与strcpy相比,memcpy并不是遇到'\0'就结束,而是一定会拷贝完n个字节。
【异常情况】从src指向的内存拷贝的长度 大于 dest指向的内存长度。
【避免策略】除了人为保证 拷贝长度 小于等于 dest指向的内存长度之外,可以封装一个安全函数
void *memcpy_safe(void *dest, ulong ulDeLen, void *src, ulong ulSrcLen)
{
if(ulDeLen < ulSrcLen) //确保不会超过目的内存块大小
{
assert();
return NULL;
}
memcpy(dest,src,ulSrcLen);
} 其中ulDeLen 指定目的内存的长度,ulSrcLen 指定要拷贝内存的长度
4、Memcmp: 比较内存区域buf1和buf2的前count个字节。(区别于strcmp)
int memcmp(const void*buf1, const void *buf2, unsigned int count);c语言中在<memory.h>或<string.h>,c++中是在<cstring>。注意:比较的时候比较的是字节,字母的时候比较的是字母的ASCII值,大的就是大,小的就小。
【异常情况】错误的以为该比较函数可以比较两个字符串 比如:
char *buf1 = (char *)malloc(10);
char *buf2 = (char *)malloc(10);
buf1 = "ab";
buf2 = "ab";
memcmp(buf1,buf2,10); // 无法判断谁大谁小 ,因为buf1与buf2申请之后没有清零,ab之后的内存区域可以为任意值
如果 memset(buf1, 0, 10);
memset(buf2, 0, 10);
buf1 = "abcd";
buf2 = "abc";
buf1 = "a";
buf2 = "a";
memcmp(buf1,buf2,10); //buf1 != buf2
参考函数:
#include "stdio.h"
#include "memory.h"
#include "stdlib.h"
int main ()
{
unsigned char *ucBufOne;
unsigned char *ucBufTwo;
ucBufOne = (unsigned char *) malloc(10);
ucBufTwo = (unsigned char *) malloc(10);
memcpy(ucBufOne, "ab", 2);
memcpy(ucBufTwo, "ab", 2);
printf("Result = %d",memicmp(ucBufOne,ucBufTwo,10));
getchar();
}
5、Strcpy:字符数组复制
char *strcpy(char* dest, const char *src); //将字符串从src中拷贝到dest中
char *strncpy(char*dest, const char *src, size_t n);// 从src中拷贝n个字符到dest中
【异常情况】拷贝的长度大于dest缓冲区长度
【避免策略】封装成安全函数 strncpy_safe(char *dest, size_t n1, char *src, size_t n2); //具体实现自己思考
6、Strcat:连接两个字符数组
char *strcat(char *dest,char *src); //将字符串src 链接到 dest后面
char *strncat(char *dest,char *src,int n);
异常情况及避免策略同上
7、Strcmp:比较两个字符数组
int strcmp(const char *s1,const char * s2); //遇到"\0"停止比较
int strncmp(char *str1, char *str2, int maxlen); //比较maxlen个字符
异常情况及避免策略同上