几种常见的字符函数和字符串函数的模拟实现

strlen

功能说明

size_t strlen ( const char * str );

字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
参数指向的字符串必须要以 ‘\0’ 结束。

strlen函数的模拟实现

思路:

1、函数传参传递的是字符串首元素的地址
2、(*str++)遍历整个字符串元素,直到遇到 ‘\0’ 停止

模拟实现strlen
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(char *str)
{
    
    
	assert(str);
	int count = 0;
	while (*str++)
	{
    
    
		count++;
	}
	return count;
}
int main()
{
    
    
	char *str = "abcdef";
	int ret = my_strlen(str);
	printf("%d",ret);
	return 0;
}

拷贝函数strcpy的模拟实现

功能说明

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

1、源字符串必须以 ‘\0’ 结束。
2、会将源字符串中的 ‘\0’ 拷贝到目标空间。
3、目标空间必须足够大,以确保能存放源字符串。
4、目标空间必须可变。

拷贝函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
void my_strcpy(char *dest, const char *src)
{
    
    
	assert(dest);
	assert(src);
	while ( *dest++ = *src++)
	{
    
    
		;
	}
}
int main()
{
    
    
	char *str1 = "abcdef";
	char arr[20] = "XXXXXXXXXXXXX";
	my_strcpy(arr, str1);
	printf("%s", arr);
	return 0;
}
思路:

1、函数参数为两个字符串数组的首元素地址。
2、while(*dest++ = *str++);此循环中当 指针src所指向的字符串遍历到’0’后,循环停止,拷贝完成。

strcat的模拟实现

功能说明

1、源字符串必须以’\0’结束。
2、目标空间必须足够大。
3、目标空间必须可变。

模拟实现strcat函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char*dest, const char*src)
{
    
    
	char*ret = dest;
	assert(dest != NULL);
	assert(src!=NULL);
	//找到目的地空间的'\0'
	while (*dest)
	{
    
    
		dest++;
	}
	//拷贝数据
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}
int main()
{
    
    
	char arr1[20] = "hello ";
	my_strcat(arr1, "world");
	printf("%s\n", arr1);
	return 0;
}
思路:

1、将两个字符串的首元素地址传给函数。
2、第一个while循环找到目的地空间的’\0’,第二个循环进行拷贝,原理同 strcpy函数。

strcmp的模拟实现

功能说明

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

int strcmp ( const char * str1, const char * str2 );
模拟实现 strcmp(比较函数)
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcmp(const char* s1,const char* s2)
{
    
    
	assert(s1);
	assert(s2);

	while (*s1 == *s2)
	{
    
    
		if (*s1 == '\0')
			return 0;
		s1++;
		s2++;
	}
	return *s1 - *s2;
}
int main()
{
    
     
	int ret = my_strcmp("abcw", "abcdef");
	if (ret < 0)
	{
    
    
		printf("小于\n");
	}
	else if (ret == 0)
	{
    
    
		printf("等于\n");
	}
	else if (ret > 0)
	{
    
    
		printf("大于\n");
	}
	return 0;
}

长度受限制的字符串操作函数

strncpy模拟实现

功能说明

char * strncpy ( char * destination, const char * source,size_t num);

1、拷贝num个字符从源字符串到目标空间。
2、如果源字符串的长度小于num,则拷贝完源字符串之后,在后面追加0,直到num个。

#include<stdio.h>
#include<string.h>
#include<assert.h>
void my_strncpy(char *dest, const char *src,size_t len)
{
    
    
	assert(dest);
	assert(src);
	int offset = 0;
	if (strlen(src) < len)
	{
    
    
		offset = len - strlen(src);
		len = strlen(src);
	}
	while (len--)
	{
    
    
		*dest++ = *src++;
	}
	while (offset--)
	{
    
    
		*dest++ = '\0';
	}
}

int main()
{
    
    
	char arr1[10] = {
    
    1,2,3,4,5,6,7,8,9,0};
	char arr2[] = "bit";
	my_strncpy(arr1,arr2,5);
	printf("%s\n",arr1);
	return 0;
}

思路:

相较于网上的其他方法,考虑到了(strlen(src) < len)的情况,两个循环相当于将拷贝分为两步,首先拷贝 src 指向的字符串,拷贝完源字符串之后,在后面追加’\0’,直到num个。

strncat连接字符串函数模拟实现

功能说明

char * strncat ( char * str1,const char * str2,size_t num);

如果str2的字符数大于n,那么该函数只将str2的前n个字符附加在str1末尾,如果str2中的字符数小于n,该字符会将str2的所有字符附加在str1末尾。无论哪种情况,都会在新字符串的末尾添加’\0’。

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncat(char*dest, const char*src,size_t n)
{
    
    
	char*ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	//找到目的地空间的'\0'
	while (*dest)
	{
    
    
		dest++;
	}
	//拷贝数据
	while (n--)
	{
    
    
		*dest++ = *src++;
	}
	return ret;
}
int main()
{
    
    
	char arr1[20] = "hello ";
	my_strncat(arr1, "world",3);
	printf("%s\n", arr1);
	return 0;
}

思路:

拷贝n个数据后停止,并在末尾加上’\0’.

strncmp 比较字符串函数模拟实现

功能说明

char * strncat ( char * str1,const char * str2,size_t num);

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncmp(const char* s1, const char* s2,size_t n)
{
    
    
	assert(s1);
	assert(s2);

	while (*s1 == *s2 && n-1>0)
	{
    
    
		if (*s1 == '\0')
			return 0;
		s1++;
		s2++;
		n--;
	}
	return *s1 - *s2;
}
int main()
{
    
    
	int ret = my_strncmp("abcw", "abcdef",3);
	if (ret < 0)
	{
    
    
		printf("小于\n");
	}
	else if (ret == 0)
	{
    
    
		printf("等于\n");
	}
	else if (ret > 0)
	{
    
    
		printf("大于\n");
	}
	return 0;
}

思路:

思路与前面 strcmp的模拟类似,在函数的实现中加入了n的约束。

	while (*s1 == *s2 && n-1>0)
	{
    
    
		if (*s1 == '\0')
			return 0;
		s1++;
		s2++;
		n--;
	}

使函数可以进行固定数目元素的比较。

子字符串查找函数 strstr

功能说明

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

判断str2是否是str1的子字符串,如果是,则返回str2在str1中首次出现的地址。

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
    
    
	assert(str1);
	assert(str2);
	const char* s1 = str1;
	const char* s2 = str2;
	const char* 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* str1 = "abcdef";
	char* str2 = "cde";
	char* ret = my_strstr(str1, str2);
	printf("%s\n", ret);
	return 0;
}

思路:

函数中定义了三个指针变量,s1,s2,cp,
1、*cp 若为’\0’,则直接返回空指针。
2、s1和s2必须满足下面条件,才能继续向后查找。

while (*s1 && *s2 && *s1 == *s2)

3、当if (*s2 == '\0')时,说明找到了子字符串,则返回cp。
4、每查找一次, 则cp++一次,cp所指向的位置就是s1下一次开始查找的位置。

内存拷贝函数 memcpy

原型:

void * memcpy ( void * dest, const void * sor, size_t num);

功能说明

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是没有意义的。

//memcpy 内存拷贝函数
//strcpy只能复制字符串,memcpy可以复制任意类型
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t count)
{
    
    
	void* ret = dest;
	assert(dest);
	assert(src);
	while (count--)
	{
    
    
		*(char*)dest = *(char*)src;
		
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
    
    
	int arr1[] = {
    
    1,2,3,4,5};
	int arr2[10] = {
    
    0};
	my_memcpy (arr2, arr1, sizeof(arr1));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d", arr2[i]);
	}
	return 0;
}

关键思路:

为使其可以进行任意类型数据的拷贝,在函数中将指针强制类型转化成(char*)类型。如下:

	while (count--)
	{
    
    
		*(char*)dest = *(char*)src;
		
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

memove 重叠拷贝

原型:

void * memmove ( void * dest, const void * sor, size_t num);

功能说明

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

//memmove重叠拷贝 模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest, void* src, size_t count)
{
    
    
	assert(dest);
	assert(src);
	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);
		}
	}
}
int main()
{
    
    
	int arr1[] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memmove(arr1 + 2, arr1, 16);
	return 0;
}

关键思路:

在进行拷贝的时候应该分为两种情况:
1、(dest<src)时。(*src)应由前往后进行拷贝。

while (count--)
		{
    
    
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}

2、(dest>src)时,(*src)应由后往前进行拷贝。

		while (count--)
		{
    
    
			*((char*)dest + count) = *((char*)src + count);
		}

猜你喜欢

转载自blog.csdn.net/du1232/article/details/109581876
今日推荐