字符处理strlen()、strcmp()、strstr()源码及改编

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

strcmp函数用来比较字符串的,strcmp函数是根据ASCII码来比较两个字符串的。若两个字符串完全相等,则返回0;若第一个字符串大于第二个字符串,则返回大于0的数值;若第一个字符串小于第二个字符串,则返回小于0的数值。
传说中的源码:(看看原理即可)

int __cdecl strcmp (const char * src, const char * dst)
{
    
    
    int ret = 0 ;
    while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
                ++src, ++dst;  
    if ( ret < 0 )
           ret = -1 ;
    else if ( ret > 0 )
           ret = 1 ;
    return( ret );
}

改编
为了减少函数参数的传参局限性,进行了如下的变动,主要是判断字符的情况看注释,关于比较大小的情况,用的时候返回的非零值情况也不多,主要是看是否相等

int str_cmp(void *str1,void *str2)
{
    
    
	uint8_t * str_1=(uint8_t*) str1;//强制转化
	uint8_t * str_2=(uint8_t*) str2;
	
	if((*str_1)=='\0'&&(*str_2)=='\0')
	{
    
    
		printf("都为空");
		return 0;
	}
	else 
	{
    
    
		while(*str_1==*str_2)
	    {
    
    
	    	str_1++;
	    	str_2++;
	    	if(*str_1==*str_2&&*str_1=='\0')
	    	{
    
           printf("不为空,且相等");
	    			return 2;
	    			
			}
		}
		printf("不为空,但是不相等");
		return 1;
	}
	
}

int strlen(const char * const s)

源码

int strlen(const char * const s)

{
    
    
int i;

for (i = 0; s[i]; i++) ;

return i;

}

改编:
三种改编,分别是常用情况,递归调用,指针写法,自行理解

int str_len1(void *str)//一般调用 
{
    
    
	uint8_t *st=(uint8_t*)str;
	uint8_t i=0;
	while(*st++!='\0')
	{
    
    
		i++;
	}
	return i;
}
int str_len2( void  *str)//递归调用 
{
    
    
	uint8_t *st=(uint8_t *)str;
	return (*st!='\0'?(1+str_len2(st+1)):0);	
} 
int str_len3(void *str)//指针写法 
{
    
    
	uint8_t *st=(uint8_t*)str;
	while(*st!='\0')
	{
    
    
		st++;
	}
	return  st-str;
}

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

strstr()函数接受两个指向字符串的指针作为参数,如果第2个字符串包含在第1个字符串中,该函数将返回第1个字符串开始的地址。若没有对应子串,则返回NULL。
源码

char * __cdecl strstr(const char *str1, const char *str2)
{
    
    
    char *cp = (char *)str1;
    char *s1, *s2;if (!*str2)
        return((char *)str1);while (*cp)
    {
    
    
        s1 = cp;
        s2 = (char *)str2;while (*s2 && !(*s1 - *s2))
            s1++, s2++;if (!*s2)
            return(cp);
​
        cp++;
    }return(NULL);
}

改编:
1)递归调用
uint8_t的使用注意调用头文件
思路:
以子串第一个字符串为基准开始在母串中遍历查找,一旦找到第一个相同的字符,开始对字串长度的数量进行比较,如果符合,此字符串为母串中第一个符合条件的字符串,反之,如果不符合回调此函数,传入的母串地址增加

uint8_t *str_(void *str_1,void *str_2)
{
    
    
	uint8_t *str1=(uint8_t*) str_1;
	uint8_t *str2=(uint8_t*) str_2;
	int len;
	uint8_t i;
	len=(uint8_t)str_len2(str_2);
	
	while(*str1!=*str2)
	{
    
    
		str1++;
		if(*str1=='\0')
		{
    
    
			return (NULL);
		}
		
	}
	for(i=0;i<len;i++)
	{
    
    
		if(*str1==*str2)
		{
    
    
			str1++;
			str2++;
		}
		else
		{
    
    
			str_(str1,str_2);
		}
	}
	return str1-len;
}

2)根据源码后改编的思路
思路:
首先判断两个字符串,如果其中一个为空,则返回NULL,从母串开始遍历

uint8_t *str_str(void *str_1,void *str_2)
{
    
    
	uint8_t *str1=(uint8_t*) str_1;
	uint8_t *str2=(uint8_t*) str_2;
	uint8_t *cp;
	uint8_t len;
	uint8_t i;
	len=str_len2(str_2);
	if(str_len2(str_2)==0||str_len2(str_1)==0)
	{
    
    
		return NULL;
	}
	while(*str1)
	{
    
    
		cp=str1;
		if(*cp==*str2)
		{
    
    
			for(i=0;i<len;i++)
			{
    
    
				if(*cp==*str2)
				{
    
    
					cp++;
			        str2++;
				}
				else
				{
    
    
					break;
				}
				
				return str1;
			
			}
			
		}
		
		str1++;
	}
	return NULL;
} 

其他
对于源码的追求是不能减少的,这样的算法很经典,值得我们模仿和学习

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/105739192
今日推荐