字符串函数详解

前言:

Hello,各位小伙伴上期我们学习了字符串操作函数中的strlen,这期我会带领大家详细介绍其他的一些字符串操作函数。我们会从格式,举例,还有模拟操作来更加深入的了解字符串操作函数。

目录

strlen的使用和模拟实现

strcpy的使用和模拟实现

 strcat的使用和模拟实现

 strcmp的使用和模拟实现

strncpy的使用和模拟实现

strncat的使用和模拟实现

strstr的使用和模拟实现 

strtok的使用


strlen的使用和模拟实现

size_t srtlen(const char*str);

 根据C++官网显示strlen的Return Value是The length of string.是将字符串长度返回。

• 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
   含 '\0' )。​
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为 size_t,是无符号的( 易错 )​
• strlen的使用需要包含头文件​----#include

 下面让我们来看一段易错题

#include 
#include 
int main()
{
 const char* str1 = "abcdef";
 const char* str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 } 
 else
 {
 printf("srt1>str2\n");
 }
 return 0;
}

如果不加思索很容易认为输出的是str1>str2,但仔细观察的话,会发现这是段代码存在bug的。

分析:strlen(str2)的计算为3,strlen(str1)的计算结果为6,相减的话为-3,但值得注意的是strlen返回的是size_t(为无符号整形 )。-3的补码为11111111 11111111 11111111 11111101,在size_t的加持下不在存在原反补的区别,计算机会认为是一个非常大的正数。

模拟实现看我上期的博文就好啦。

strcpy的使用和模拟实现

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

 根据C++官网显示strcpy的Return Value是destination is returned.是将目标地址返回。

• 源字 符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷贝到目标空间。
• 目标空间必须足够大,以确保能存放源字符串。
• 目标空间必须可修改。

 strcpy通常是将两个字符串拼接到一起将source复制到destination当中。

下面我们来看看该如何模拟实现吧。

//模拟实现strcpy
#include
#include
char* my_strcpy(char*dest,const char*src)
{
    char* ret = dest;
	assert(dest && src);
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;

	}
	*dest = *src;
	return ret;
}
int main()
{
	char arr1[] = "hello world";
	char arr2[30] = { 0 };
	char*ret = my_strcpy(arr2, arr1);
	printf("%s", ret);
	 
	return 0;
}

在这里详细介绍一下函数实现部分: 

因为返回值是dest的首地址,但后面的++过程中,dest的首地址会改变。所以会引入一个新的变量将dest的首地址存放起来,最后在返回。同时*src为0后不在进行赋值运算,所以在while循环后面还会有一个赋值运算这里主要是将src的 '\0' 赋值到dest中去。

 我们可以将函数定义部分进行代码的优化并进行分析:

char* my_strcpy(char*dest,const char*src)
{
    char* ret = dest;
	assert(dest && src);
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

这样看确实优化了不少但也变得烧脑了,*src++为后置++,会先使用在++,*src首先会将w赋值给*dest,为真进行++后变为o重复上述操作,直到*src的值为d的时候将d的值赋值给*dest后++,*str变为\0并赋值给*dest,此时整个表达式变为0,为假不在向后进行。但此时将\0赋值给了dest完成了所有操作。

 strcat的使用和模拟实现

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

根据C++官网显示的strcat的Return Value 是destination is returned. 同样也是将目标首地址返回。

• 源字符串必须以 '\0' 结束。
• 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
• 目标空间必须有足够的大,能容纳下源字符串的内容。
• 目标空间必须可修改。

#include
#include
char*my_strcat(char*dest,const char*src)
{
    char *ret = dest;
    assert(dest&&src);
    while(*dest)
    {
        dest++;
    }
    while(*dest++ = *src++)
    {
        ;
    }
    
    return ret;
}
int main ()
{
    char arr1[] = "world";
    char arr2[30] = "hello ";
    char* ret = my_strcat(arr2,arr1);
    printf("%s",arr2);
    return 0;
}

追加的过程:

•首先找到dest的第一个\0。

•然后从\0开始追加源头字符串。

•原头字符串中的\0也要追加到dest中去。

 strcmp的使用和模拟实现

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

根据C++的官网显示strcmp的Return Value的值为Returns an integral value indicating the relationship between the strings:

return value indicates
<0 the first character that does not match has a lower value in ptr1 than in ptr2
0 the contents of both strings are equal
>0 the first character that does not match has a greater value in ptr1 than in ptr2

• 第一个字符串大于第二个字符串,则返回大于0的数字​ 。
• 第一个字符串等于第二个字符串,则返回0​ 。
• 第一个字符串小于第二个字符串,则返回小于0的数字 。​ 

strcmp是用来比较两个字符串的大小。(注意:不是比较字符串的长度而是在相同位置下所占字符的ASCLL的大小)

strcmp的模拟实现:

#include
#include
int *my_strcmp(const char*str1,const char*str2)
{
    assert(str1&&str2);
    while(*str1 == *str2)
    {
        if(*str1 == '\0')//此时用来判断当*str1==*str2后,如果*str1和*str2都已经到最后'\0',比较
            return 0;//完了后,全部相等返回0
        str1++;
        str2++;
        
    }
    return *str1-*str2;//解引用后返回二者的差值来进行判断,由主函数中的ret来进行接收(强制类型转化成int类型)
}
int main ()
{
    char arr1[] = "abcdef";
    char arr2[] = "abce";
    int ret = my_strcmp(arr1,arr2);
    if(ret<0)
        printf("<\n");
    else if(ret==0)
        printf("=\n");
    else
        printf(">\n");
}

上面我们介绍了strlen,strcpy,strcat,strcmp的使用及模拟实现但上述字符串函数都存在缺陷,比如我们要将一个arr1[ ]="abcdef"中的前三个拷贝到arr2[ ]={ 0 }中去的话,显然strcpy不可以进行操作,为了解决此问题设计了函数:strncpy,strncat,strncmp。

strncpy的使用和模拟实现

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

相比较strcpy而言,传参部分多出了一个size_t num是用来传递需要拷贝的个数。

根据C++的官网显示strcmp的Return Value的值为destination is returned.

使用如下:

#include
#include
int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = { 0 };
	strncpy(arr2, arr1, 4);
	printf("%s", arr2);
	return 0;
}//运行结果为abcd

模拟实现:

#include
#include
char* my_strcpy(char* str2, char* str1, size_t num)
{
	assert(str1 && str2);
	int i = 0;
	char* ret = str2;
	for (i = 0; i < num; i++)
	{
		*(str2 + i) = *(str1 + i);
	}
	
	return ret;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[30] = "**********************";
	char* ret = my_strcpy(arr2, arr1, 5);
	printf("%s", ret);
	return 0;
}

strncat的使用和模拟实现

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

同样相比较strcat而言,strncat指定了要追加的字符长度。

根据C++的官网显示strcmp的Return Value的值为destination is returned.

使用:

#include
#include
int main ()
{
    char arr1[] = "good ";
    char arr2[] = "morning or night ";
    strncat(arr1,arr2,7);
    printf("%s",arr1);
}//运行结果为good morning

模拟实现:

#include

#include
char *my_strncat(char* dest, const char* src,size_t num)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest)
	{
		dest++;
	}
	while (num--)
	{
		*dest++ = *src++;
	}
	*dest = '\0';
	return ret;
}
int main()
{
	char arr1[30] = "good ";
	char arr2[] = "morning or night";
	char *ret = my_strncat(arr1, arr2,7);
	printf("%s", ret);
	return 0;
}

strcnmp的使用:

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

和strcmp的使用类似,多出一个指定长度的变量。这里就不在详细表述了。我们详细介绍一下strstr的使用和模拟实现。

同时小编在进行调试的时候发现会产生一些错误比如:在观察arr1和arr2的时候发现无法进行观察会显示字符串中的字符无效,这是因为在vs上有两种版本一个是debug版本另一个是release版本 ,调试的时候只能在debug版本中使用。

strstr的使用和模拟实现 

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

Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(函数返回字符串str2在字符串str1中第一次出现的位置)。​
The matching process does not include the terminating null-characters, but it stops there.(字符的比较匹配不包含 \0 字符,以 \0 作为结束标志)。

简单描述的话就是在str1中寻找str2,并且打印从str1中str2以后的字符串。 

#include
#include
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char *ptr = strstr(arr1, arr2);
	if (ptr == NULL)
		printf("没有找到");
	else
		printf("找到了,%s\n", ptr);
return 0;
}//输出结果为找到了,bcdef

 模拟实现:
 

#include
#include
char *my_strstr(const char*str1, const char*str2)
{   
    assert(str1&&str2);
    const char *s1 = str1;
    const char *s2 = str2;//str1和str2始终指向起始位置
    const char *cur = str1;//cur来记录每次开始匹配的位置
    if(*str2 == '\0')//当str2是空字符串的时,直接返回str1
        return str1;
    while(*cur)
    {
        //完成一次匹配
        s1 = cur;
        s2 = str2;
        while(*s1 == *s2)
        {
            s1++;
            s2++;
        }
        if(*s2 == '\0')
            return cur;
        cur++;
    } 
    return NULL;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char *ptr = my_strstr(arr1, arr2);
	if (ptr == NULL)
		printf("没有找到");
	else
		printf("找到了,%s\n", ptr);
return 0;
}

strtok的使用

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

• sep参数指向一个字符串,定义了用作分隔符的字符集合​
• 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
• strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
• strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
• strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针。

#include 
#include 
int main()
{
 char arr[] = "192.168.6.111";
 char* sep = ".";
 char* str = NULL;
 for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
 {
 printf("%s\n", str);
 }
 return 0;
}

 OK,这就是本期要分享的内容啦,欢迎各位小伙伴来指正。

你可能感兴趣的:(算法,运维,c语言,开发语言)