C语言字符串函数 之 库函数模拟实现

目录

1.模拟实现strlen

2.模拟实现strcpy

3.模拟实现strcat 

4.模拟实现strstr

5.模拟实现strcmp

6.模拟实现memcpy

7.模拟实现memmove 


1.模拟实现strlen

我们都知道这个函数是用来记录‘\0’之前字符的个数的(不包含‘\0’)。那么我们将如何实现呢?

接下来,博主将以三种方式模拟实现strlen函数。

方式1:常规遍历,当*str == 0时便自动会停下来

//计数器方式
int my_strlen(const char* str)
{
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	char* arr[] = { "abcdefg" };
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

方式2:利用函数递归实现

//不能创建临时变量计数器
int my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}


int main()
{
	char* arr[] = { "abcdefg" };
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

方式3:原理:指针-指针会得到两个指针之间的字符个数

//指针-指针的方式
int my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')
		p++;
	return p - s;
}


int main()
{
	char* arr[] = { "abcdefg" };
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

2.模拟实现strcpy

 这个函数会将源数据拷贝到目标数据中。

//1.参数顺序
//2.函数的功能,停止条件
//3.assert
//4.const修饰指针
//5.函数返回值
//6.题目出自《高质量C/C++编程》书籍最后的试题部分
char *my_strcpy(char *dest, const char*src)
{
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;
}

int main()
{
    char arr1[1000] = { "abcdefg" };
    char arr2[] = { "aaaa" };
    char* ret = my_strcpy(arr1, arr2);
    printf("%s", ret);
    return 0;
}

 char  *  strcpy(char  *  destination,  const  char  *  source)

所以我们模拟时候,参数是先放目标字符串,再放源字符串

而我们的停止条件,当*dest++ = *src++; dest 和 src只要有一方为'\0'那么就停止了

assert的作用就是判断dest 和 src是否为空指针的,他的头文件为 #include<assert.h>

至于const,则是为了防止src这个源字符串被修改,我们要改的只是dest。

至于函数返回值ret,我们可以看到他是一个指针,他返回的是目标空间的起始地址

注意:这个函数会把源字符串中的'\0'拷贝到目标文件

3.模拟实现strcat 

 这个函数是将源字符串拷贝到目标字符串的后面。实现代码如下:

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest)
	{
		dest++;
	}
	while ((*dest++ = *src++))
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[1000] = { "abcdef" };
	char arr2[] = { "aaaaa" };
	char* ret = my_strcat(arr1, arr2);
	printf("%s", ret);
	return 0;
}

原理:就是先把目标字符串给遍历到‘\0’的位置,然后再把源字符串一一拷贝进去。

注意:这里需要先把目标字符串的起始位置拷贝下来,因为strcat函数返回的是目标空间的起始位置。

4.模拟实现strstr

这个函数是在目标字符串中找源字符串第一次出现的位置。找到位置,就返回第一次出现的位置,找不到就返回NULL。

#include<stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
	const char* s1;//遍历str1指向的字符串
	const char* s2;//遍历str2指向的字符串
	const char* cp;//记录str1遍历的起始位置
	cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;
		cp++;


	}
	return NULL;
}

int main()
{
	char arr1[] = "abbaabababadefg";
	char arr2[] = "bababa";
	char * ret = my_strstr(arr1, arr2);
	if (ret == NULL)
		printf("找不到");
	else
	printf("%s", ret);
	return 0;
}

这里最好不要动str1和str2,让cp去记录str1的起始位置,s1和s2分别代替str1和str2去遍历字符串。当*s1 == *s2时,就进入循环,让s1++和s2++,如果*s2 == 0,就说明找到了,这时候就可以返回cp;当*s1 不等于 *s2时,那就让cp++,然后再进行判断是*s1是否等于*s2;当cp指向str1的末尾,也就是'\0'时,那么就说明找不到了,这个时候返回NULL即可。当然这里还要考虑s1和s2是否为空的情况,在while循环中,已经体现了这点。

5.模拟实现strcmp

strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。

int my_strcmp(const char* p, const char* s)
{
	assert(p && s);
	while (*p++ == *s++)
	{
		;
	}
	if (*p == 0)
		return 0;
	if (*p > *s)
		return 1;
	else
		return -1;

}

int main()
{
	char arr1[] = "abcde";
	char arr2[] = "abcc";
	int ret = my_strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

由于我们只是对两个字符串进行比较,不改变其内容,所以我们首先可以加上const修饰,其次我们应该对他们进行assert判断,防止空指针的情况,接着便是通过while循环把两者相同的字符遍历过去,到他们字符不相同的地方,然后进行比较即可。

6.模拟实现memcpy

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t sz)
{
	void* ret = dest;
	assert(dest && src);
	while (sz--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[100] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	my_memcpy(arr1, arr2, 20);


	return 0;
}

需要注意的点就是这里把dest和src强制转化成(char*)类型,是为了方便比较,一个字节一个字节比较,方便不同类型的数据进行比较。

7.模拟实现memmove 

void* my_memove(void* des, const void* src,size_t sz)
{
    void* ret = des;
    assert(des && src);
    if(des < src)
   {
    //从前到后
    int i = 0;
    for(i = 0; i < sz; i++)
    {
      *(char*)des = *(char*)src;
      des = (char*)des + 1;
      src = (char*)src + 1;
    }
     }
  else
     //从后到前
  while(sz--)
   {
      *(char*)des + sz = *(char*)src + sz;
   }
    return ret;
}
int main()
{
  int arr[] = {1,2,3,4,5,6,7,8,9,10};
  my_memove(arr,arr+2,20);
  int i = 0;
  for(i = 0; i < 10; i++)
  {  
     printf("%d",arr[i]);
  }
    return 0;
}

为了防止数据提前丢失,导致结果错误,这里需要注意就是,当dest < src时,我们应该采用从前到后的方式,当dest > src时,我们应该采用从后到前的方式。 

举个例子:

这里dest 是 arr,  src 是 arr+2,我们可以发现dest在src的前面,所以dest < src的,我们需要从前往后,如果从后往前,7换到5,6换到4,这个时候的5就不是原来的5了,已经给前面换成7了。

猜你喜欢

转载自blog.csdn.net/A1546553960/article/details/133971071
今日推荐