【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove …]

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove …],希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

1.模拟实现strlen

2.模拟实现strcpy

3.模拟实现strncpy

4.模拟实现strcat

5.模拟实现strncat

6.模拟实现strcmp

7.模拟实现strncmp

8.模拟实现strstr

9.模拟实现strtok

10.模拟实现memcpy

11.模拟实现memmove

12.模拟实现memcmp

13.模拟实现memset



1.模拟实现strlen

注意:

size_t strlen ( const char * str );

1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )。

2.参数指向的字符串必须要以 ‘\0’ 结束。

3.注意函数的返回值为size_t,是无符号的

模拟实现:

#include<stdio.h>
size_t My_strlen(const char* str)//求字符串长度不需要更改原字符串,const修饰更安全
{
	assert(str);//保证指针有效性
	int count = 0;
	while (*str++)
	{
		count++;
	}
	return count;
}

int main()
{
	char str[] = { "abcdef" };
	printf("len = %u",My_strlen(str));
	return 0;
}

递归模拟实现:

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

int main()
{
	char str[] = { "abcdef" };
	printf("len = %d\n",My_strlen(str));
	return 0;
}

2.模拟实现strcpy

注意:

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

1.源字符串必须以 ‘\0’ 结束。

2.会将源字符串中的 ‘\0’ 拷贝到目标空间。

3.目标空间必须足够大,以确保能存放源字符串。

4目标空间必须可变。

模拟实现:

char* My_strcpy(char* dest, const char* scr)//字符串拷贝不需要更改源字符串,const修饰更安全
{
	assert(dest && scr);//保证指针有效性
	char* _dest = dest;
	while (*dest++ = *scr++)
	{
		;
	}
	return _dest;
}

int main()
{
	char dest[] = { "hello" };
	char scr[] = { "world" };
	
	printf("%s", My_strcpy(dest, scr));
	return 0;
}

3.模拟实现strncpy

模拟实现:

char* My_strncpy(char* dest, const char* src, size_t sz)
{
	assert(dest && src);//保证指针有效性
	char* ret = dest;
	while (sz--)
	{
		*dest++ = *src++;
	}
	*dest = '\0';//strncpy的特性,覆盖后结尾加上\0
	return ret;
}

int main()
{
	char str1[] = { "abcdef" };
	char str2[7] = { 0 };
	printf("%s\n",My_strncpy(str2, str1, 3));
	return 0;
}

4.模拟实现strcat

注意:

char * strcat ( char * destination, const char * source );

1.源字符串必须以 ‘\0’ 结束。

2.目标空间必须有足够的大,能容纳下源字符串的内容。

3.目标空间必须可修改。

模拟实现:

char* my_strcat(char* arr,const char* cat)
{
	assert(arr && cat);//保证指针有效性
	char* tmp = arr;
	//while (*arr++)不能这样写,因为到\0时出循环后还会++,跳过\0
	//{
	//	;
	//}
	while (*arr != '\0')//先找到尾部,再追加
	{
		arr++;
	}
	while (*arr++ = *cat++)
	{
		;
	}
	return tmp;
}

int main()
{
	char arr[10] = { "abc" };
	my_strcat(arr, "def");
	printf("%s", arr);
	return 0;
}

5.模拟实现strncat

模拟实现:

char* My_strncat(char* dest, const char* src, size_t sz)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest)
	{
		dest++;
	}
	while (sz--)
	{
		*dest++ = *src++;
	}
	*dest = '\0';
	return ret;
}

int main()
{
	char str1[15] = { "hello " };
	printf("%s",My_strncat(str1, "painoworld", 5));
	return 0;
}

6.模拟实现strcmp

注意:

int strcmp ( const char * str1, const char * str2 );

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

2.第一个字符串等于第二个字符串,则返回0

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

模拟实现:

int My_strcmp(const char* arr1,const char* arr2)
{
	assert(arr1 && arr2);//保证指针有效性
	while (*arr1 == *arr2)
	{
		if (*arr1 == '\0')//同时为\0的情况,其他时候若有一方为\0就会在while()判断里跳出循环
		{
			break;
		}
		arr1++;
		arr2++;
	}
	return *arr1 - *arr2;//直接通过相减的方式判断大小更加简便
}

//为也可以这样写

int My_strcmp(const char* arr1, const char* arr2)
{
	assert(arr1 && arr2);//保证指针有效性
	while (*arr1 == *arr2 && *arr1)
	{
		arr1++;
		arr2++;
	}
	return *arr1 - *arr2;//直接通过相减的方式判断大小更加简便
}

int main()
{
	char arr1[] = { "abcdz" };
	char arr2[] = { "abcda" };
	int ret = My_strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("==\n");
	}
	else if (ret > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

7.模拟实现strncmp

模拟实现:

int My_strncmp(const char* str1, const char* str2, size_t sz)
{
	assert(str1 && str2);
	while (*str1 == *str2 && sz != 1)
	{
		sz--;
		str1++;
		str2++;
	}
	return (*str1 - *str2);
}

int main()
{
	char str1[] = { "hello" };
	char str2[] = { "hel" };
	int ret = My_strncmp(str1, str2, 3);
	if (ret == 0)
	{
		printf("==");
	}
	else if(ret > 0)
	{
		printf(">");
	}
	else
	{
		printf("<");
	}
	return 0;
}

8.模拟实现strstr

注意:

char * strstr ( const char *str1, const char * str2);

1.如果 str2 不是str1返回指向 str1 中第一次出现的 str2 的指针。

模拟实现:

char* My_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);//保证指针有效性
	const char* s1 = str1; //记录起始位置
	const char* s2 = str2;
	const char* p = str1; //图文解释
	while (*p) //检测p是否为\0,如果是,说明已经找完母串,却未发现字串
	{
		s1 = p;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && * s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//如果字串已经遍历到\0,说明找完了,并且找到了,此时p所指向的就是与子串开始匹配的地址
		{
			return p;
		}
		p++;
	}
	return NULL;
}

int main()
{
	char str1[] = "abbbcdef";
	char str2[] = "bbc";
	char* p = My_strstr(str1, str2);
	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("找到了\n");
	}
	return 0;
}

此函数模拟稍有难度,可以看下图解释:

情况一:

【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove ...]

这里通过循环判断s1 == s2就可一次得出判断结果

情况二 :

第一次相遇:

【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove ...]

第二次相遇:

【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove ...]

第三次相遇:

【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove ...]

此时*s1 = b; *s2 = c; 所以证明不是字串。

真的是这样吗?

        仔细观察,bbc确实是他的字串啊!

        但是根据情况一,只靠循环一股脑的遍历下去是不行的…

        因此再引入一个指针变量p来记录位置就十分有必要了

【C语言】字符函数的模拟实现 [ strlen(含递归)、strcpy、strncpy、strcat、strncat、strcmp、strstr、strtok、memcpy、memmove ...]

当*s1与s2*第一次相等是就用p指针记录下来,如果s1与s2继续向后比较,发现不匹配了难道要继续向后走吗?当然行不通的,像这种bbc情况就会错过这对有缘人啊~ 这时,我们只需让s1继续回到刚刚指针p记录的位置的下一个位置,让s2回到起始位置,继续相互比较即可。


9.模拟实现strtok

注意:

char * strtok ( char * str, const char * sep );

1.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)

2.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。

3.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

4.如果字符串中不存在更多的标记,则返回 NULL 指针。

模拟实现:

char* My_strtok(char* str, const char* sep)
{
	assert(sep);//保证指针有效性
	char* s1 = NULL;//记录初地址
	static char* p = NULL;//记录字符串位置
	static int count = 0;//记录分隔符位置
	if (str == NULL)
	{
		count++;
		p++;
	}
	else
	{
		p = str;
	}
	s1 = p;//记录每次传入子串的初始地址
	while (*p != *(sep + count) && *p != '\0' && (sep + count) != '\0')
	{
		p++;
	}
	if (*p == *(sep + count))//如果与分隔符相等,则置为\0,并返回s1
	{
		*p = '\0';
		return s1;
	}
	else
	{
		return NULL;
	}
}
int main()
{
	const char* sep = "@.";//分隔符
	char email[] = { "chenyikang@gitee.com" };//待被分割的对象
	char tmp[30] = { 0 };//strtok会修改原串,每分割一次会将原串中的分隔符改为\0,所以创造了这个零时字符串
	strcpy(tmp, email);
	char* ret = NULL;
	for (ret = My_strtok(tmp, sep);
		ret != NULL;
		ret = My_strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
	return 0;
}

10.模拟实现memcpy

注意:

void * memcpy ( void * destination, const void * source, size_t num );

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

2.这个函数在遇到 ‘\0’ 的时候并不会停下来。

3.如果source和destination有任何的重叠,复制的结果都是未定义的。

模拟实现:

void* My_memcpy(void* dest, const void* scr, size_t sz)
{
	assert(dest && scr);//保证指针有效性
	int ret = dest;
	while(sz--)
	{   //由于传入的是字节数,所以只需要强制类型转化成char*类型,
		//解引用后为char类型一个一个字节覆盖就okk
		*(char*)dest = *(char*)scr;
		((char*)dest)++;
		((char*)scr)++;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	My_memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

11.模拟实现memmove

注意:

void * memmove ( void* destination, const void * source, size_t num );

模拟实现:

void* My_memmove(void* dest, const void* src, size_t sz)
{
	assert(dest && src);//保证指针有效性
	int ret = dest;
	//有时需要从前往后处理,有时需要从后往前处理,不能直接认为从后往前覆盖解决一切问题!
	//当dest 再 src 左边,需要从前向后
	if (dest < src)
	{//前->后
		while (sz--)
		{
			*(char*)dest = *(char*)src;
			((char*)dest)++;
			((char*)src)++;
		}
	}
	else
	{//后->前
		while (sz--)
		{
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	My_memmove(arr1+2, arr1, 12);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

12.模拟实现memcmp

注意:

int memcmp ( const void * str1, const void * str2, size_t num );

模拟实现:

int My_memcmp(const int* arr1, const int* arr2, size_t sz)
{
	assert(arr1 && arr2);
	while (*(char*)arr1 == *(char*)arr2 && sz != 1)
	{
		sz--;
		((char*)arr1)++;
		((char*)arr2)++;
	}
	return (*(char*)arr1 - *(char*)arr2);
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 1,3,3};
	int ret = My_memcmp(arr1, arr2, 12);
	if (ret == 0)
	{
		printf("==");
	}
	else if(ret > 0)
	{
		printf(">");
	}
	else
	{
		printf("<");
	}
	return 0;
}

13.模拟实现memset

注意:

void* memset(void* ptr, int value, size_t sz)

模拟实现:

void* My_memset(void* ptr, int value, size_t sz)
{
	assert(ptr);
	void* ret = ptr;
	while (sz--)
	{
		*((char*)ptr) = value;
		((char*)ptr)++;
	}
	return ptr;
}

int main()
{
	char str[] = { "hello world" };
	My_memset(str, 'x', 5);
	printf("%s", str);
	return 0;
}

码字不易~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129916.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!