【C语言】字符串函数的模拟实现

各位读者老爷好,基于上篇文章我介绍了一些字符函数和字符串函数,那么我现在来实现一些字符串函数!

目录

1.模拟实现strlen

1.计数器方式

2.递归方式(不能创建临时变量计数器) 

3.指针减指针的方式 

2.模拟实现strcpy

3.模拟实现strcat

4.模拟实现strcmp

5.模拟实现strstr

6.ending 


1.模拟实现strlen

可以回顾一下strlen函数的大致功能:strlen函数是一个获取字符串长度的函数,计算的是字符串'\0'之前字符的个数。

1.计数器方式

模拟如下:

size_t my_strlen(const char* str)
{
	int count = 0;//计算不为'\0'的字符数
	while (*str)//循环遍历字符串str的字符,若为'\0'则停止
	{
		count++;
		str++;
	}
	return count;
}

该方法思想很简单,循环遍历字符串中不为'\0'的字符,创建临时变量count来统计这些字符的个数并将count返回即可。

#include <stdio.h>
size_t my_strlen(const char* str)
{
	int count = 0;//计算不为'\0'的字符数
	while (*str)//循环遍历字符串的字符,若为'\0'则停止
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char string1[] = "abcdefg";
	size_t ret = my_strlen(string1);
	printf("%zd\n", ret);

	char* string2 = "abc\0efg";
	ret = my_strlen(string2);
	printf("%zd\n", ret);

	return 0;
}

运行结果是7和3,这里就不展示了哦!

2.递归方式(不能创建临时变量计数器) 

模拟如下:

size_t my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

这个方法的思想也不难,利用了递归的思想,画图方便理解:

#include <stdio.h>
size_t my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}
int main()
{
	char string1[] = "abcdefg";
	size_t ret = my_strlen(string1);
	printf("%zd\n", ret);

	char* string2 = "abc\0efg";
	ret = my_strlen(string2);
	printf("%zd\n", ret);

	return 0;
}

运行结果也是7和3,这里也不展示了!

3.指针减指针的方式 

模拟如下:

size_t my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')//循环遍历字符串使指针变量p指向'\0'
		p++;
	return p - s;
}

这个方法思路也不难,创建临时指针变量p,再循环遍历字符串使指针变量p指向'\0'。因为指针减去指针得到的是两个指针内存位置之间相隔的元素个数(不是字节数),所以将p-s返回即可。

#include <stdio.h>
size_t my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')//循环遍历字符串使指针变量p指向'\0'
		p++;
	return p - s;
}
int main()
{
	char string1[] = "abcdefg";
	size_t ret = my_strlen(string1);
	printf("%zd\n", ret);

	char* string2 = "abc\0efg";
	ret = my_strlen(string2);
	printf("%zd\n", ret);

	return 0;
}

运行结果也是7和3,这里也不展示了!

2.模拟实现strcpy

可以回顾一下strcpy函数的大致功能:strcpy函数是一个复制字符串的函数,将源字符串复制到目标数组中,复制包括源字符串的'\0'(并在'\0'处停止)。

模拟如下:

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;//记录目标空间起始地址
	assert(dest && src);//断言防止dest或src为空指针
	while (*src!='\0')//循环将源字符串不为'\0'的字符拷贝给目标数组
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//将'\0'从源字符串拷贝给目标数组
	return ret;//返回目标空间起始地址
}

根据strcpy函数的功能,我们只要先用循环语句将源字符串中不为'\0'的字符拷贝给目标数组,每拷贝一次,形参dest和src各自向后跳一个字节指向下一个字符。当循环停止时,src指向源字符串的'\0',再将'\0'拷贝给目标数组。返回目标数组起始地址即可。

上述代码我们还可以优化,对于优化代码,就不分析了,感兴趣的小伙伴可以自己研究哦: 

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);//断言
	while ((*dest++ = *src++))
	{
		;
	}
	return ret;
}

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);//断言
	while ((*dest++ = *src++))
	{
		;
	}
	return ret;
}
int main()
{
	char string1[] = "abxxefghijk";
	char* string2 = "cd";
	char* ret = my_strcpy(string1 + 2, string2);
	printf("%s\n", ret);
	printf("%s\n", string1);
	return 0;
}

运行结果为:"cd"和"abcd"。这里就不展示了。对于这个结果的原因,我们来可以分析一下:因为通过my_strcpy函数将字符数组string1在内存中更改成了:"abcd\0fghijk\0" 。所以易知打印结果为上述结果。

3.模拟实现strcat

可以回顾一下strcat函数的大致功能:strcat函数是一个将源字符串追加到目标字符串的函数。从目标字符串的'\0'开始向后依次被源字符串的字符覆盖,两者串联形成新的字符串(将源字符串的'\0'也拷贝过去覆盖了,新字符串的末尾包含'\0')。

模拟如下:

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;//记录目标空间起始地址
	assert(dest && src);//断言防止dest或src为空指针
	while (*dest)//循环使dest指向目标字符串的'\0'
	{
		dest++;
	}
	while ((*dest++ = *src++))//循环,从目标字符串的'\0'开始向后依次被源字符串的字符覆盖
		                      //(包括源字符串的'\0')
	{
		;
	}
	return ret;//返回目标空间的起始地址
}

对于这个模拟实现来说,思路也不算难。strcat函数与strcpy函数最大区别是strcat函数是要在指向目标字符串的指针变量dest开始向后找到目标字符串的'\0',再从'\0'的位置依次拷贝源字符串的字符覆盖掉目标字符串;而strcpy函数则直接从传入的目标字符串地址出开始依次拷贝源字符串的字符覆盖目标字符串!所以my_strcat函数的实现上,加上寻找目标字符串的'\0'这一步,其它的与strcap函数模拟实现一致即可。

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;//记录目标空间起始地址
	assert(dest && src);//断言防止dest或src为空指针
	while (*dest)//循环使dest指向目标字符串的'\0'
	{
		dest++;
	}
	while ((*dest++ = *src++))//循环,从目标字符串的'\0'开始向后依次被源字符串的字符覆盖
		                      //(包括源字符串的'\0')
	{
		;
	}
	return ret;//返回目标空间的起始地址
}
int main()
{
	char string1[] = "hello wo\0xd!";
	char* string2 = "rld";
	char* ret = my_strcat(string1 , string2);
	printf("%s\n", ret);
	printf("%s\n", string1);
	return 0;
}

运行结果是''hello world"和"hello world"。这里均没打印感叹号,就是因为感叹号被'\0'给覆盖掉了。 

4.模拟实现strcmp

老样子可以回顾一下strcmp函数的大致功能:strcmp是一个比较两个字符串的函数。这个函数开始比较每个字符串的第一个字符,如果它们彼此相等,就继续比较每个字符串的下一个字符(即比较两个字符串对应位置上字符的ASCII值大小),直到字符不同或遇到'\0'为止。

函数返回值指示两个字符串之间的关系如下:

1.第一个字符串大于第二个字符串,则返回大于0的数字
2.第一个字符串等于第二个字符串,则返回0
3.第一个字符串小于第二个字符串,则返回小于0的数字

模拟如下:

int my_strcmp(const char* src, const char* dst)
{
	assert(src && dst);//断言
	while (*src == *dst)//两字符串字符相等的情况
	{
		if (*src == '\0')//字符相等且为'\0'的情况
		{
			return 0;
		}
		dst++;
		src++;
	}
	return *src - *dst;//两字符串字符不相等时返回其差值
}

strcmp函数的模拟实现思路也不难。循环遍历两个字符串对应字符,若相应字符相等:则判断是否为'\0',若均为'\0'说明两个字符串遍历完了,返回0即可;若均不为'\0',跳过一个字符判断下一个字符是否相等。若对应字符不相等,跳出循环,返回两个不相等字符的差值即可。

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* src, const char* dst)
{
	assert(src && dst);//断言
	while (*src == *dst)//两字符串字符相等的情况
	{
		if (*src == '\0'&&*dst=='\0')//字符相等且为'\0'的情况
		{
			return 0;
		}
		dst++;
		src++;
	}
	return *src - *dst;//两字符串字符不相等时返回其差值
}
int main()
{
	char string1[6] = "abcd";
	char string2[6] = "abc";
	int ret = my_strcmp(string1, string2);
	printf("%d\n", ret);

	char str1[6] = "abc";
	char str2[6] = "abc";
	ret = my_strcmp(str1, str2);
	printf("%d\n", ret);

	char arr1[6] = "abc";
	char arr2[6] = "abcd";
	ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

运行结果为100、0和-100。结果是没毛病的哦!

5.模拟实现strstr

同样的,我们可以来回顾一下strstr函数的大致功能:strstr函数是一个定位子串的函数。strstr函数有两个形参,第1个形参是一个被const修饰的char*类型的指针变量 str1,指向要扫描的字符串;第2个形参是一个被const修饰的char*类型的指针变量str2,指向要匹配的字符串(子串)。返回值是一个char*类型的指针变量,有3种情况:如果能在被扫描的字符串中(定位)找到子串,返回的指针变量指向被扫描字符串中子串第一次出现的位置;如果被扫描字符串中不存在这个子串,返回空指针;如果str2指向'\0',直接返回str1。

模拟如下:

char* strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);//断言
	char* cp = (char*)str1;//指针变量cp记录子串中被扫描字符串初始位置
	char* s1, * s2;//分别用来遍历被扫描字符串字符和子串字符
	if (!*str2)//若str2指向'\0',直接返回str1;
		return((char*)str1);
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && !(*s1 - *s2))//若两字符不等或两个字符串任一遍历完停止
			s1++, s2++;
		if (!*s2)//若s2指向'\0',子串全找到,返回子串初次在被扫描字符串出现的位置
			return(cp);
		cp++;
	}
	return(NULL);//找不到,返回空指针
}

这个模拟实现的思路比较难表达,感兴趣的小伙伴可以去观看https://www.bilibili.com/video/BV1Vm4y1r7jY?p=124&vd_source=eef5b921666f3c5956eceb46489c8cf0 

这个视频1小时16分钟开始有详细讲解!

#include<stdio.h>
#include<assert.h>
char* strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);//断言
	char* cp = (char*)str1;//指针变量cp记录子串中被扫描字符串初始位置
	char* s1, * s2;//分别用来遍历被扫描字符串字符和子串字符
	if (!*str2)//若str2指向'\0',直接返回str1;
		return((char*)str1);
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && !(*s1 - *s2))//若两字符不等或两个字符串任一遍历完停止
			s1++, s2++;
		if (!*s2)//若s2指向'\0',子串全找到,返回子串初次在被扫描字符串出现的位置
			return(cp);
		cp++;
	}
	return(NULL);//找不到,返回空指针
}
int main()
{
	char string1[] = "hi,hello world!";
	char string2[] = "he";
	char* ret = strstr(string1, string2);//找的到
	printf("%s\n", ret);

	char str1[] = "hi,hello world!";
	char str2[] = "he!";
	ret = strstr(str1, str2);//找不到
	printf("%s\n", ret);
	return 0;
}

运行结果为:"hello world!"和(NULL)。结果没毛病哈!

6.ending 

感谢读者老爷阅读,可以的话请点赞关注,祝你天天开心呀!有错误也可以私信我哦!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X_chengonly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值