当我们在模拟字符串函数的时候需要注意两点:
■ 检查参数合法性
■ 对指针进行参数保护
注意点:
字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
参数指向的字符串必须要以 ‘\0’ 结束。
注意函数的返回值为size_t,是无符号的(易错)。
//注意返回值是size_t
size_t my_strlen(const char *string) {
assert(string!=NULL); //1.检查参数合法性
const char* src = string; //2.对指针进行参数保护
size_t len = 0; //长度需要和返回值对应
while (*src++ != '\0') {
len++;
}
return len;
}
strcpy
注意点:
源字符串必须以 ‘\0’ 结束。
会将源字符串中的 ‘\0’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
char* my_strcpy(char* strDest, const char* strSrc)
{
assert(strDest != NULL && strSrc != NULL); //1检查参数合法性
char* pDest = strDest;
const char* pSrc = strSrc; //2 保护参数
while (*pDest++ = *pSrc++); //先将*pSrc的值赋给*pDest,然后判断pSrc的值是不是'\0'然后pSrc++,pDest++;
//当然也可以这样写
/*
while(*pSrc!='\0'){
*pDest=*pSrc;
pDest++;
pSrc++;
}
*pDest='\0';
*/
return strDest;
}
strcat
提示:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
char* my_strcat(char* strDest, const char* strSrc)
{
assert(strDest!=NULL&&strSrc!=NULL);//1.检查参数的合法性
char* pDest = strDest; //2.对参数指针进行保护
const char* pSrc = strSrc;
//先找到strSrc的'\0'的位置
while (*pDest !='\0') {
pDest++;
}
//实行连接拷贝
while (*pSrc!='\0') {
*pDest++ = *pSrc++;
}
//增加结束标记
*pDest = '\0';
return strDest;
}
strcmp
//string1>string2 返回值大于0
//string1=string2 返回值等于0
//string1
int my_strcmp(const char* string1, const char* string2)
{
assert(string1!=NULL&&string2!=NULL); //1.参数合法性检查
const char* ps1 = string1; //2.指针进行参数保护
const char* ps2 = string2;
while (*ps1!='\0'||*ps2!='\0') {
//当存在两个字符串没有同时到达末尾就循环 当同时到达末尾时,res=0即字符串相等
if (*ps1 - *ps2 != 0) //当存在两个字符不相等时就跳出循环,即使有一个字符串达到字符串末尾。我们在(*ps1-*ps2)进行统一判断。
break;
ps1++;
ps2++;
}
int res = *ps1 - *ps2;
return res;
}
函数原型通过添加count值来限制所能操作字符串的长度。
strncpy
char* my_strncpy(char* strDest, const char* strSrc,size_t count)
{
assert(strDest != NULL && strSrc != NULL); //1检查参数
char* pDest = strDest;
const char* pSrc = strSrc; //2 保护参数
while (count--) {
*pDest++ = *pSrc++;
}
return strDest;
}
strncat
说 明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
char* my_strncat(char* strDest, const char* strSrc, size_t count)
{
assert(strDest!=NULL&&strSrc!=NULL);
char* pDest = strDest;
const char* pSrc = strSrc;
while (*pDest !='\0') {
pDest++;
}
while (count--) {
*pDest++ = *pSrc++;
}
*pDest = '\0';
return strDest;
}
strncmp
int my_strncmp(const char* string1, const char* string2,size_t count)
{
assert(string1 != NULL && string2 != NULL); //1.参数合法性检查
const char* ps1 = string1; //2.指针进行参数保护
const char* ps2 = string2;
while (--count) {
//要先减了再判断是不是>0,因为ps1++,ps2++会提前到达下一个字符
if (*ps1 - *ps2 != 0) //当存在两个字符不相等时就跳出循环,即使有一个字符串达到字符串末尾。我们在(*ps1-*ps2)进行统一判断。
break;
ps1++;
ps2++;
}
int res = *ps1 - *ps2;
return res;
}
就是说这个标准规定memcpy是不处理的。但是基于编译器 可能会处理也可能不会处理。但是对于memmove这个标准规定是一定会处理的
memcpy
■ 函数memcpy从src的位置开始向后复制num个字节的数据到des的内存位置。以字节为单位进行复制。
■ 这个函数在遇到 ‘\0’ 的时候并不会停下来。
■ 如果source和destination有任何的重叠,复制的结果都是未定义的。
void* my_memcpy(void* dest, const void* src, size_t count) {
assert(dest&&src); //检查参数合法性
char* pdest = (char *)dest;//指针进行参数保护
const char* psrc = (const char*)src;
while (count--) {
*pdest++ = *psrc++;
}
return dest;
}
memmove
■ 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
■ 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
内存重叠:拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。
原型:void* my_memmove(void* dest, const void* src, size_t count);
解决办法:
■ 判断是否内存重叠,内存重叠从后往前复制。
■ 没有内存重叠,从前往后复制。
void* my_memmove(void* dest, const void* src, size_t count) {
assert(dest&&src);
char* pdest = (char *)dest;
const char* psrc = (const char*)src;
if (pdest>psrc&&pdest<psrc+count) {
//判断有内存重叠
pdest = pdest + count - 1; //从后往前赋值
psrc = psrc + count - 1;
while (count--) {
*pdest-- = *psrc--;
}
}
else {
//没有内存重叠的情况
while (count--) {
*pdest++ = *psrc++;
}
}
return dest;
}
memmove和memcpy的唯一区别:在C语言标准中规定当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。memcpy只是不保证结果的正确性,但是结果也有可能是正确的,这取决于自己的编译器。有一些编译器memcpy函数也是处理了内存局部重叠的情况。
memcmp
int my_memcmp(const void* buf1, const void* buf2, size_t count)
{
assert(buf1&&buf2);
const char* pbuf1 = (const char*)buf1;
const char* pbuf2 = (const char*)buf2;
while (count--) {
if (*pbuf1 - *pbuf2 != 0)
break;
pbuf1++;
pbuf2++;
}
return (*pbuf1-*pbuf2);
}
memset
void* my_memset(void* dest, int c, size_t count)
{
assert(dest);
char* pdest = (char*)dest;
while (count--) {
*pdest++ = c;
}
return dest;
}