C语言的深入——搞定字符串函数

引言:在本文章中,我们将进阶讨论C语言字符串函数的问题,即将之前的内容总结并引入一些新内容。
作者:小 琛
欢迎转载,请标明出处

strlen函数

功能:得到某字符串的长度
我们在MSDN上寻找strlen的原型函数以及头文件,看下图
在这里插入图片描述
也就是说,strlen函数的参数必须是 "const char * ",且要包含头文件<string.h>
模拟实现:

#include <stdio.h>
/******************************
函数功能:测量字符串长度函数
入口参数:字符串指针
返回值:测量的数字
*******************************/
unsigned int my_strlen(const char *str)
{
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
/******************************
函数功能:测量字符串长度函数(递归写法)
入口参数:字符串指针
返回值:测量得到的数字
*******************************/
unsigned int my_strlen1(const char *str)
{
	if (*str == '\0')
	{
		return 0;
	}
	return 1+my_strlen1(str + 1);
}

strcpy函数

函数定义:char *strcpy( char *strDestination, const char *strSource );
函数功能:将第二个字符串的内容拷贝到第一个字符串,因此第二个字符串为const char *
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。

模拟实现:

/******************************
函数功能:字符串拷贝函数
入口参数:目标字符串和原字符串
返回值:目标地址
*******************************/
char* my_strcpy(char *destination,const char* source)
{
	char* ret = destination;
	assert(source != NULL);
	assert(destination != NULL);
	while (*destination++ = *source++)
	{
		;
	}
	return ret;
}

strcat函数

函数原型:char *strcat( char *strDestination, const char *strSource );
函数功能:将一个字符串追加到另一个字符串的后面
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。

模拟实现:

/******************************
函数功能:字符串追加
入口参数:目标字符串和原字符串
返回值:目标地址
*******************************/
char* my_strcat(char* destination, const char* source)
{
	char* ret = destination;
	assert(source != NULL);
	assert(source != NULL);
	while (*destination != \0)
	{
		destination++;
	}
	while ((*destination++ = *source++) != '\0')
	{
		;
	}
	return ret;
}   

strcmp函数

函数原型:int strcmp( const char *string1, const char *string2 );
函数功能:比较两个字符串,直到找到某个不相同的或遇到’\0’。
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
比较使用的是ASCLL码表
模拟实现:

/******************************
函数功能:字符串比较
入口参数:两个不可修改的字符串
返回值:0、1、-1
*******************************/
int my_strcmp(const char* str1, const char* str2)
{
	int count = 0;
	assert(str1 != NULL);
	assert(str2 != NULL);
	while ((*str1) && (*str2) && (!(count = *(unsigned int*)str1 - *(unsigned int*)str2)))
	{
		str1++;
		str2++;
	}
	if (count > 0)
		return 1;
	else if (count < 0)
		return -1;
	else
		return 0;
}

strncpy、strncat、strncmp的用法

字符串库有之前三个函数加n的用法,其作用类似:从第n个开始进行操作,这几个函数不需要进行模拟,但是要学会使用

strncpy

原型:char *strncpy( char *strDest, const char *strSource, size_t count );
作用:将第二个字符串的n个字符拷贝到第一个参数内
例子:

int main()
{
	char *p = "good";
	char str[20] = "terrible";
	strncpy(str, p, 4);
	printf("%s", str);
	return 0;
}

结果:
在这里插入图片描述

strncat

函数原型:char *strncat( char *strDest, const char *strSource, size_t count );
函数功能:将参数2的n个字符追加到参数1后
例子:

int main()
{
	char *p = "good";
	char str[20] = "terrible";
	strncat(str, p, 2);
	printf("%s", str);
	return 0;
}

结果:
在这里插入图片描述

strncmp

函数原型:int strncmp( const char *string1, const char *string2, size_t count );
函数功能:比较前n个字符,相同返回0,不同返回1或-1

int main()
{
	char *p = "good";
	char *q = "goxx";
	int i = 0;
	i=strncmp(p, q, 2);
	printf("%d", i);
	return 0;
}

在这里插入图片描述

strstr函数

函数原型:char *strstr( const char *string, const char *strCharSet );
函数功能:在字符串1中查找另一个字符串2首次出现的位置。如果找到匹配的字符串,返回第一次匹配到的字符串的指针,否则返回NULL。
使用例子:

int main()
{
	char str[] = "This is a simple string";
	char *pch;
	pch = strstr(str, "simple");
	puts(pch);
	return 0;
}

结果:
在这里插入图片描述
模拟实现:

/******************************
函数功能:寻找字符串2在字符串1的地址
入口参数:两个不可修改的字符串
返回值:一个地址
*******************************/
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);
	char* cp= (char*)str1;
	char* sub=(char*)str2;
	char* s1=NULL;
	if (*str2 == '\0')
		return NULL;
	while (*cp)
	{
		s1 = cp;
		sub = (char*)str2;
		while (sub&&s1 && (*sub == *s1))
		{
			sub++;
			s1++;
		}
		if (*sub == '\0')
			return cp;
		cp++;
	}
}

memcpy函数

引言:在使用strcpy的时候,我们可以注意到,strcpy的定义是通过‘\0’实现的,但假如出现一种情况,要拷贝的字符串内含有‘\0’怎么办?memcpy则可以实现
函数原型:void *memcpy( void *dest, const void *src, size_t count );
函数功能:拷贝参数2的n个内容到参数1
strcpy和memcpy主要有以下3方面的区别。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

使用范例:

int main()
{
	char *str = "This is a \0 simple string";
	char q[40];
	memcpy(q, str, 25);
	puts(q);
	return 0;
}

结果:
在这里插入图片描述
模拟实现:

/******************************
函数功能:拷贝函数
入口参数:一个可修改和一个不可修改的指针
返回值:一个地址
*******************************/
void* my_memcpy(void* dest, const void* source,unsigned int count)
{
	void* ret = dest;
	assert(dest);
	assert(source);
	while (count--)
	{
		*(char*)dest = *(char*)source;
		dest=(char*)dest+1;
		source = (char*)source + 1;
	}
	return ret;
}

memmove函数

函数原型:void *memmove( void *dest, const void *src, size_t count );
引言:我们在实现拷贝的时候,会遇到拷贝的空间出现重叠的情况。而空间重叠又有两种情况,如下图
在这里插入图片描述
在这里插入图片描述
结合memcpy模拟的内容,我们可以得出:第一种情况是无法使用memcpy的,原因是会将仍然有用的部分覆盖掉。
这里就要引入另一个函数,memmove函数,该函数在写法上与memcpy类似,只是它兼容了上述的情况,而如何实现该函数呢?
我们根据上图不难得出:
当dest<src,我们应该使用从前往后拷贝
当dest>src,我们需要使用从后往前拷贝
而无重叠部分,任意方法都可以

(这里的从前往后与从后往前都是针对拷贝内容src的)
因此,根据以上逻辑就可以模拟memmove函数

/******************************
函数功能:兼容覆盖区域的拷贝函数
入口参数:一个可修改、一个不可修改的指针、拷贝长度
返回值:一个地址
*******************************/
void* my_memmove(void* dest, const char* src, unsigned int count)
{
	assert(dest);
	assert(src);
	void* ret = dest;
	if (dest < src || (char*)dest >= ((char*)src + count))
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		dest = (char*)dest + count - 1;
		src = (char*)src + count - 1;
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest - 1;
			src = (char*)src - 1;
		}
	}
	return ret;
}

到此,博文结束。
感谢浏览。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值