字符串库函数理解和模拟再现(strlen,strcpy,strcat,strcmp,strncpy,strncat,strncmp,strstr,strtok)

strlen

size_t  strlen( const char* str )

作用:是计算字符串的字符个数

原理:是计算字符串在'\0'前出现的字符个数('\0'是字符串结束的标志)

返回类型是size_t,因为strlen求字符个数不管怎样得到的都是正整数。

(用size_t的缺点:两个size_t类型的数相减时,因为类型是size_t,所以结果必定是正整数,必要时要用强制类型转换)

const char* str,const修饰的是*p,也就是p所指向的字符串的值不能变。(不能通过p这个指针去改str的值,str的值还是能修改的)(如果不要改变字符串,习惯在*p前加上const)

如果是char*const str,const修饰的是指针变量p,就是p所指向的地址不能变。

使用方法:

char arr[] = "abcdefg";
int ret = strlen(arr);

创建了个数组放字符串,数组元素[a,b,c,d,e,f,g,\0],arr是数组首元素地址,也就是字符串地址,strlen会从得到的地址开始往后走,直到走到\0,然后计算走过的字符个数,ret就是字符个数。

模拟再现

1.用循环的方式

int my_strlen(const char* str)
{
	assert(str != 0);
	int count = 0;
	while (*str)
	{
		str++;
		count++;
	}
	return count;
}

assert是用于检测指针是否是空指针,如果是空指针就会报错

每经过一个字符,就会判断是否是0('\0'),如果不是,就继续向下走,同时计数加一。

2.用递归的方式

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

如果不是'\0',就返回1加上(下一个地址是否为'\0',否,加一)

3.指针-指针

int my_strlen(const char* str)
{
	assert(str != 0);
	const char* start = str;
	while (*str)
	{
		str++;
	}
	return str - start;
}

和第一种方法类似,只不过这次就不会走一步记一个数,而是一直走到'\0',然后拿走到'\0'的地址减去开始的地址,指针-指针得到的是中间的元素个数(char类型),就会的到中间的字符个数。

strcpy

char* strcpy(char*str1 , const char*str2)

作用:字符串拷贝,前一个str1是目标,后一个str2是源头,把源头空间的字符串拷贝到目标空间

原理:从源头空间开始找,直到找到'\0',停止,然后把源头空间的字符串连同'\0'一起拷贝到目标空间。返回的是目标空间的首元素地址

要求:1.源数据一定要有'\0',否则无法判断要拷贝的字符串结尾在哪。2.目标空间必须足够大,能放的下从源空间拷贝过去的字符。3.目标空间大小必须可变。

使用方法:

	char arr1[20] = "";
	char arr2[] = "abcdef";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);

打印出来的结果是:abcdef.

模拟再现:
 

char *my_strcpy(char* str1, const char* str2)
{
	char* ret = str1;
	assert(str1 && str2);
	while (*str1++ = *str2++)
	{
		;
	}
	return ret;//返回目标空间首元素
}

ret就是目标空间首元素地址,在while循环的判断条件中,同时完成了字符的复制,以及当str2到达'\0'即*str2=0,就会自动停下(判断条件为0,是假)

strcat

char* strcat (char* str1,const char*str2)

作用:对目标空间追加源空间的内容

原理:找到目标空间'\0'处,作为追加的开始地点,源空间的'\0'处作为追加内容的结束点,把源空间的追加内容,加到目标空间的'\0'处(会覆盖'\0')

要求:目标空间和源空间都要有'\0',目标空间要足够大且可修改大小。

使用方法:

char arr[20] = "abcd";
strcat(arr, "cccsss");
printf("%s\n", arr);

结果是abcdcccsss(在abcd后面加上了cccsss)

模拟再现:

char* my_strcat(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* ret = str1;
	//1.找目标空间的\0
	while (*str1 != '\0')
	{
		str1++;
	}
	//2.追加
	while(*str1++=*str2++)
	{
		;
	}
	return ret;
}

目标空间从头开始找'\0',找到了'\0',的地址,就从这里开始追加源空间的字符串,直到源空间找到'\0'

strcmp

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

作用:用于比较两个字符串的大小

原理:不是比较字符串的长度,而是从头开始一个一个比较字符的ascill码值,

str1>str2,返回一个>0的正数,

str1<str2,返回一个<0的负数,

str1=str2,返回0。

(在vs环境下,这个>0和<0,返回的是1,-1,但是其他的编译器可能不是这样的)

使用方法:

char arr1[] = "abcdef";
char arr2[] = "abcd";
int ret =strcmp(arr1, arr2);
printf("%d", ret);

这里可以把这两个字符串想象成两个数,比大小从最高位往下看,a是它们的最高位,最高位相同,看下一位,b是第二高位,第二位也相同,看第三位......第五位,arr1是e,arr2是0,e的ascill码值大于0,就不用看更低的位了,arr1>arr2。如果arr2是abcdf,在第五位arr1的e小于arr2的f,就是arr1<arr2。

模拟再现

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)//从最高位往下找找到不同的那一位(那个地址)
	{
		if (*str1 == '0')//如果位数相同,又相等,可能会同时到空的0(没字符的地方),这个时候就要停下来了,不能再继续找不同的地方了。
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
	//return *str1-*str2;
	//别的编译器下的情况,不是所有编译器返回值是1,-1。
}

strcpy

strcat

strcmp

这三个是长度不受限制的字符串函数,会不安全,想要限制长度,用下面下面三个。 

strncpy

char* strncpy(const char*str1,const char*str2,size_t num)

和strncpy一样,只不过后面多出了size_t num,num是选择要拷贝几个字符

若num大于源空间中的字符数,就会拿'0'来补齐,再拿去拷贝到目标空间。

strncat

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

可选择 追加内容选源空间中的几个字符,不够拿'0'凑

strncmp

int strncmp(const char*str1,const char*str2,size_t num)

可选择 比较的字符串长度是多少

strstr

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

作用:在str1中查找str2第一次出现的位置。(查找子字符串)

返回的是 str1中第一次找到str2的地址 (指针)

模拟再现

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')
		return str1;

	const char* s1 = str1;
	const char* s2 = str2;//str1,str2各给一个指针
	const char* cp = str1;//str1再给个指针
	while (*cp)//在str1一步一步找,找到\o前,一直循环
	{
        //每次循环进去   
		s1 = cp;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//找到str1,str2相同的地方,开始核对str2剩下的字符能否对的上
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;//没找到str1中的一个字符(cp)和str2首字符(s2)相同的地方,str1向前推进一位
	}
	return NULL;
}

strtok

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

作用:通过sep中的分隔符切分字符串

char arr[]="yuqi@gmail.com";
char*p="@.";
strtok(arr,p)

其中@和.是分隔符,放在p中

找到第一个分隔符处,把它替换成\0,如果第一个参数是NULL,会从上一次\0处,继续开始找下一个分隔符切割(这个函数会改变字符串,同时也会在函数里记录字符串中的一些地址(变成\0的地方))

返回的是被分隔的第一串字符串的地址

一般用法:

strcpy(buf,arr);//会改变字符串,用临时的buf来实现效果,这样就不会改到arr上了
for(ret=strtok(buf,p);ret!=NULL;ret=strtok(NULL,p))
{
    printf("%s\n",ret);
}

结果:

yuqi

gmail

com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值