模拟实现C函数库中的常用函数
在接下来的描述中,一共会模拟实现 7 个库函数,分别是:
1、strlen 2、strcpy 3、strcat 4、strstr 5、strcmp 6、memcpy 7、memmove
在模拟实现之前,我都会先把函数在MSDN中的定义截取下来并适时解释。
常用函数:
1、模拟实现strlen
下面我们将用三种方式分别来模拟实现strlen:
#include <stdio.h>
#include <assert.h>
//1、计数法
int MyStrlen_1(const char* str) //const保证str所指向内容不能被改变
{
int count = 0; //计数变量
assert(str != NULL);
while (*str++)
{
count++;
}
return count;
}
//2、递归
int MyStrlen_2(const char* str)
{
assert(str != NULL);
if (*str == '\0')
{
return 0;
}
return 1 + MyStrlen_2(str + 1);
}
//3、指针
int MyStrlen_3(char* str)
{
char *p = str;
assert(str != NULL);
while (*p)
{
p++;
}
return p - str;
}
int main()
{
char *p = "abcdef";
printf("%d\n", MyStrlen_1(p)); //6
printf("%d\n", MyStrlen_2(p)); //6
printf("%d\n", MyStrlen_3(p)); //6
return 0;
}
以上三种方式中,我更倾向于第一种,因为第二种是使用递归的方法,我们都知道递归的弊处在于栈溢出,而第三种,参数不能用const修饰,这就导致,我们有可能会改变str所指向的内容。综合比较,第一种方法比较好。
2、模拟实现strcpy
下面是模拟实现:
#include <stdio.h>
#include <assert.h>
char* MyStrcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = { 0 };
MyStrcpy(arr1, "lxt");
printf("%s\n", arr1);
return 0;
}
3、模拟实现strcat
下面是模拟实现:
#include <stdio.h>
#include <assert.h>
char* MyStrcat(char *dest, const char *src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
//1、找到目标字符串的结尾
while (*dest)
{
dest++;
}
//2、在末尾添加源字符串
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr2[20] = "Hello ";
MyStrcat(arr2, "World");
printf("%s\n", arr2);
return 0;
}
4、模拟实现strstr
下面是模拟实现:
#include <stdio.h>
#include <assert.h>
char* MyStrstr(const char* str, const char* substr)
{
char *s1 = NULL;
char *s2 = (char*)substr;
char *cur = (char*)str;
assert(str != NULL);
assert(substr != NULL);
if (*substr == '\0')
{
return (char*)str;
}
while (*cur)
{
s1 = cur;
s2 = substr;
while(*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cur;
}
cur++;
}
return NULL;
}
int main()
{
const char *str1 = "abbbbbbbbcdef";
char *ret = MyStrstr(str1, "bbc");
if (ret == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
5、模拟实现strcmp
下面将用两种方法分别模拟实现:
#include <stdio.h>
#include <assert.h>
int MyStrcmp_1(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int MyStrcmp_2(const char* str1, const char* str2)
{
int ret = 0;
assert(str1 != NULL);
assert(str2 != NULL);
while (!(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1)
{
++str1;
++str2;
}
if (ret < 1)
{
return - 1;
}
else if (ret > 1)
{
return 1;
}
return ret;
}
int main()
{
char *p = "abcdef";
char *q = "abbbbbbbb";
int ret = MyStrcmp_1(p, q);
int ret = MyStrcmp_2(p, q);
if (ret == 0)
{
printf("p = q\n");
}
else if (ret > 0)
{
printf("p > q\n");
}
else
{
printf("p < q\n");
}
return 0;
}
6、模拟实现memcpy
下面是模拟实现:
#include <stdio.h>
#include <assert.h>
void* MyMemcpy(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[10] = { 0 };
int arr2[] = { 1,2,3,4,5 };
MyMemcpy(arr1, arr2, 20);
return 0;
}
需要注意的是,函数的参数类型为void* ,void类型不支持赋值和解引用,故在实现内部,需强转成 char* ,原因是count不是元素个数,指字节数。
7、模拟实现memmove
下面是模拟实现:
#include <stdio.h>
#include <assert.h>
void* MyMemmove(void* dest, const void* src, size_t count)
{
void* ret = dest;
assert(dest != NULL);
assert(src != NULL);
if (dest < src)
{
//前 --> 后
while(count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后 --> 前
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 };
MyMemmove(arr1 + 2, arr1, 16);
return 0;
}