c语言strcpystrcmpstrcat等常见字符操作函数的介绍
Posted aaaaaaaWoLan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言strcpystrcmpstrcat等常见字符操作函数的介绍相关的知识,希望对你有一定的参考价值。
字符串是c语言中一种常见的数据类型,字符串属于常量,不可修改,如果我们想要修改,就要把它放在字符数组中来对其进行修改,而有一些函数可以帮助我们完成一些常用的操作字符串的动作,下面我们就来介绍一些常用字符串操作函数
strlen
strlen的作用是计算字符串的长度,但不包括最后的\\0
所以我们在传参的时候要注意是不是以\\0结尾的字符串
我们先来看函数原型
size_t strlen ( const char * str );
形参是用一个字符指针接收字符串的首字符地址
返回类型是个无符号的整型,因为字符串的长度肯定是个非零的数,但这里有一个地方需要注意,看下面:
#include <stdio.h>
int main()
{
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)//strlen返回的是一个无符号的整型,相减的结果数值上等于-3
//但转化为无符号整型是一个无穷大的数
{
printf("str2>str1\\n");
}
else
{
printf("srt1>str2\\n");
}
return 0;
}
所以打印结果是str2>str1
strlen的使用情况并不是很复杂,接下来模拟实现strlen:(解释见代码注释)
方法1:
计数器实现
int my_strlen1(const char* str)//计数器实现strlen
{
assert(str);//判断str是否为空指针
int count = 0;
while (*str++)//str先进行后置++,再进行解引用操作
//如果*str != \\0,进入循环计数
{
count++;//进入循环一次使count自增一次
}
return count;//当循环结束时,count此时就是字符串的长度
}
int main()
{
char arr[] = "hello world";
printf("%d\\n", my_strlen1(arr));
return 0;
}
方法2:
递归实现
int my_strlen2(const char* str)
{
if (*str)//如果*str != \\0,进入递归
return 1 + my_strlen2(str + 1);//返回1+剩下的字符串长度
else//当*str = \\0,返回0,此时就可计算出字符串长度
return 0;
}
int main()
{
char arr[] = "hello world";
printf("%d\\n", my_strlen2(arr));
return 0;
}
方法3:
指针减指针实现
int my_strlen3(const char* str)//指针-指针实现strlen
{
assert(str);
char* start = str;//记录首字符地址
while (*str)//*str != \\0时,str指针跳向下一个字符的地址
{
str++;
}
return str - start;//循环结束时,str指向最后一个字符(不是\\0),
//str - start即为两者之间元素的个数,也就是字符串长度
}
int main()
{
char arr[] = "hello world";
printf("%d\\n", my_strlen3(arr));
return 0;
}
我们也可以看看vs2019提供的strlen:
size_t __cdecl strlen (
const char * str
)
{
const char *eos = str;
while( *eos++ ) ;
return( eos - str - 1 );
}
求字符串长度时i,字符串不可写成arr[] = {‘a’, ‘b’, ‘c’}的形式,否则计算的是随机值,因为该数组末尾是没有\\0的
strcpy
我们对数组赋值时不能写成 arr = “abcd”,arr表示的是数组名,这种赋值方式是不合法的,这时就可以使用strcpy
strcpy的作用是将一个字符串的内容拷贝到另一个字符串
strcpy的原型:
char* strcpy(char * destination, const char * source );
参数是两个字符串,将第二个参数的内容拷贝至第一个参数
返回类型是第一个字符串的首字符地址
使用strcpy应注意的点:
1.源字符串必须以 ‘\\0’ 结束。
2.会将源字符串中的 ‘\\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。否则会导致数组越界访问
4.目标空间必须可变。必须要是可修改的数组
我们同样来实现strcpy:
char* my_strcpy(char* dst, const char* src)
{
assert(dst && src);
char* start = dst;//记录首字符地址,以便返回
while (*dst++ = *src++)// \\0也会被拷贝到arr1中
{
;
}
return start;
}
int main()
{
char arr1[20] = "hello world";
char arr2[] = "didididi";
printf("%s\\n", strcpy(arr1, arr2));
}
strcat
strcat是将一个字符串的内容连接在另一个字符串的后面
函数原型:
char * strcat ( char * destination, const char * source );
将第二个参数的内容连接在第一个参数之后
返回第一个字符串首字符地址
使用strcat需要注意的地方:
1.源字符串必须以 ‘\\0’ 结束。’\\0’也会被赋给目标字符串
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
字符串自己给自己连接可以吗?
不可行,我们先模拟实现strcat,知道原理后再解释
char* my_strcat(char* dst, const char* src)//模拟实现strcat
{
assert(dst && src);
char* start = dst;
while (*dst)//找到目标字符串的末尾
{
dst++;
}
while (*dst++ = *src++) //当把源字符串中的'\\0'赋给目标字符串后,返回目标字符串的首元素地址
{
;
}
return start;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
printf("%s\\n", my_strcat(arr1, arr2));
return 0;
}
了解strcat的原理后,我们就知道,源字符串必须要有’\\0’连接才会结束
而如果自己连接自己,会导致’\\0’被覆盖掉,因此就没有了结束标志,此时代码就陷入死循环的连接。
strcmp
int strcmp ( const char * str1, const char * str2 );
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
strcmp是对两个字符串进行比较,比较的不是字符串的长度,而是字符中字母的大小(a<b<…<z,大写也一样)
比如abcd大于abbc
如果对应字符相等,则向后继续判断
模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)当两个字符串对应元素相等时,向后继续比较
{
if (*str1 == '\\0')//如果两元素都等于'\\0'了,说明两字符串相等,返回0
return 0;
str1++;
str2++;
}
return *str1 - *str2;//当两字符串不相等时,返回对应ASCII码差值
}
int main()
{
char arr1[30] = "zbc";
char arr2[] = "abb";
printf("%d\\n", my_strcmp(arr1, arr2));
return 0;
}
vs2019的参考实现代码:
int __cdecl strcmp (
const char * src,
const char * dst
)
{
int ret = 0 ;
while((ret = *(unsigned char *)src - *(unsigned char *)dst) == 0 && *dst)
//当两字符串对应元素相等并不为'\\0'时,往后继续比较
//而当两字符串对应元素相等但已经等于'\\0'时,跳出循环,此时ret=0e
{
++src, ++dst;
}
return ((-ret) < 0) - (ret < 0); // (if positive) //- (if negative) generates branchless code
//如果对应str1(第一个参数)对应字符大于str2(第二个参数)对应字符,ret大于0,此时(-ret)<0为真,ret<0为假
//两个表达式相减得1,故此时返回值为1
//如果对应str1(第一个参数)对应字符小于str2(第二个参数)对应字符,ret小于0,此时(-ret)<0为假,ret<0为真
//两个表达式相减得-1,故此时返回值为-1
}
strncpy
函数原型:
char * strncpy ( char * destination, const char * source, size_t num );
strncpy的作用是拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标空间的后边追加\\0,直到第num个字符。
我们可以来验证一下:
int main()
{
char arr1[30] = "hello world";
char arr2[] = "hey";
strncpy(arr1, arr2, 5);//5大于arr2的长度
return 0;
}
可以看到在把hey拷贝给arr1后,还拷贝了两个\\0,即5-3个\\0
这里就不实现strncpy了,大家有兴趣可以自行实现
strncat
函数原型:
char * strncat ( char * destination, const char * source, size_t num );
与strncmp类型,在目标字符串后追加源字符串中num个字符
但当num大于源字符串长度时,只会在源字符串后加1个\\0,这一点与strncmp不同
我们同样可以证明:
int main()
{
char arr1[30] = "hello\\0 world";
char arr2[] = "aaa";
strncat(arr1, arr2, 7);//7大于arr2的长度
return 0;
}
因为连接字符串是从目标字符串的\\0开始的,所以在初始化arr1时就加上了\\0,方便我们观察连接后arr1的变化
可以看到只追加了一个\\0,之后的’l’ 'd’仍然存在
看一个使用strncat的例子:
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");//str1中被拷贝了To be
strcpy (str2,"or not to be");//str2中被拷贝了or not to be
strncat (str1, str2, 6);//将str2中的6个字符连接到str1后
puts (str1);
return 0;
}
打印结果为:
To be or not
strncmp
函数原型:
int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
使用:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");//寻找R2开头的字符串
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)//当返回0时,说明找到了R2开头的字符串
{
printf ("found %s\\n",str[n]);
}
return 0;
}
str中有两个R2开头的字符串,所以打印结果即为这两个字符串
结果为:
strstr
strstr是判断一个字符串是否是另一个字符串的子串,即是否包含了另一个字符串
函数原型:
char * strstr ( const char *str1, const char *str2);
判断str2是否为str1的子串
如果是,则返回str1中对应str2字符串的首字符地址
如果不是,则返回空指针
使用例子:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");//判断simple是否为This is a simple string的子串
//pch即为's'(第三个s)的地址
strncpy (pch,"sample",6);//将sample从pch处开始拷贝
puts (str);
return 0;
}
pch即为’s’(第三个s)的地址
打印结果是This is a sample string
模拟实现strstr:
char* mystrstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == 0)
return (char*)str1;
const char* sign = str1;//记录第一个相等字符的位置
const char* s1 = str1;//用来移动并查找是否与str2相等,因为没找到要跳回sign位置,所以用另外一个指针进行移动
const char* s2 = str2;用来移动并查找是否与str1相等,因为没找到要跳回str2位置,所以用另外一个指针进行移动
for (; *s1; s1 = sign + 1, s2 = str2)//可以省略初始化条件,判断条件为s1不指向\\0
//调整部分为每次将s1重新返回,s2也返回
{
sign = s1;//标记位置
while ((*s1) && (*s1 == *s2))//当s1不指向'\\0'且*s1 == *s2相等时,继续判断是否相等
{
s1++;
s2++;
if (*s2 == '\\0')//当s2指向'\\0'时,说明str2是str1的子串,返回一个相等字符的位置
return (char*)sign;
}
}
return NULL;//当循环结束时,说明没找到该子串,返回NULL
}
int main()
{
char arr1[30] = "abbbcdef";
char arr2[] = "";
printf("%s\\n", mystrstr(arr1, arr2));
return 0;
}
或者:
char* mystrstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == 0)
return (char*)str1;
const char* sign = str1;
const char* s1 = str1;
const char* s2 = str2;
while (*sign)//*sign != '\\0'说明还可以继续查找,否则就没有找到
{
s1 = sign;//将s1置于标记处
s2 = str2;//将s2至于str2起始位置
while (* s1 && *s1 == *s2)//当s1不指向'\\0'且*s1 == *s2相等时,继续判断是否相等
{
s1++;
s2++;
if (*s2 =='\\0')//当s2指向'\\0'时,说明str2是str1的子串,返回一个相等字符的位置
return (char*)sign;
}
sign++;//继续往下查找
}
return NULL;//循环结束时锁说明没有找到,返回NULL
}
以上就是一些常见的字符串操作函数,有兴趣的小伙伴还可以自己了解以下两个函数:
strtok
strerror
strtok
char * strtok ( char * str, const char * sep );
sep参数是个字符串,定义了用作分隔符的字符集合 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \\0 结尾,每次调用成功则返回指向被分割出片段的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将通过指针保存它在字符串中的位置。
函数保存的指针在下一次调用中将作为起始位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
以下是两个简单的例子
大家可以自行打印试试感受下这个函数的作用
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \\"%s\\" into tokens:\\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
int main()
{
char *p = "1993868303@qq.com";
const char* sep = "@.";
char arr[30];
char *str = NULL;<以上是关于c语言strcpystrcmpstrcat等常见字符操作函数的介绍的主要内容,如果未能解决你的问题,请参考以下文章