前言:
Hello,各位小伙伴上期我们学习了字符串操作函数中的strlen,这期我会带领大家详细介绍其他的一些字符串操作函数。我们会从格式,举例,还有模拟操作来更加深入的了解字符串操作函数。
目录
strlen的使用和模拟实现
strcpy的使用和模拟实现
strcat的使用和模拟实现
strcmp的使用和模拟实现
strncpy的使用和模拟实现
strncat的使用和模拟实现
strstr的使用和模拟实现
strtok的使用
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的加持下不在存在原反补的区别,计算机会认为是一个非常大的正数。
模拟实现看我上期的博文就好啦。
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完成了所有操作。
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中去。
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。
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;
}
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版本中使用。
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;
}
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,这就是本期要分享的内容啦,欢迎各位小伙伴来指正。