系列文章目录
字符函数和字符串函数详解(一)strlen strcpy strcat strcmp
字符函数和字符串函数详解(二)strncpy strncat strncmp strstr strtok(及其模拟实现)
字符函数和字符串函数详解(三)strerror memcpy memmove memset memcmp(及部分字符分类函数)
目录
二.长度不受限制的字符串函数 strcpy strcat strcmp
这一系列专门做c语言中的字符和字符串函数的使用教程,和常遇见的相关错误的原因和规避错误要注意的要点。(第一期:strlen strcpy strcat strcmp)
一.求字符串长度的函数strlen
1.strlen
(1)strlen的使用
c语言中的strlen函数是为了统计字符串中"\0"出现之前的字符个数,当在字符串中出现"\0"时便会停止计数。换言之,如果想统计字符串的长度,则该字符串的结尾就必须要有"\0"。否则strlen就会继续往后面的内存中查找,直到找到"\0"为止。
int main()
{
char arr[] = "abcdefg"; //在字符串中默认在结尾处会有一个"\0"
printf("%d\n", strlen(arr)); //此处返回的便是七
}
为了验证strlen函数是遇到"\0"时停止计数,我们可以在字符串中自己添加一个"\0",看它的返回结果是否会发生变化
int main()
{
char arr[] = "abc\0defg"; //我们在c的后面添加了\0,strlen会在找到"\0"时停止计数
printf("%d\n", strlen(arr)); //此时返回的结果应该是3
}
(2)strlen使用时的注意事项
1.我们在统计字符串长度时,万不可写出下面的代码:
//错误示范
int main()
{
char arr[] = { 'a', 'b', 'c' };
printf("%d\n", strlen(arr));
return 0;
}
因为在这个数组中是没有"\0"的,strlen函数再继续往内存后面查找,这是极其危险的。
2.当我们当要比较俩个字符串长度的代码的时候,我们会常常写出如下代码。
//错误示范
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
printf(">\n");
else
printf("<\n");
return 0;
}
//我们常常认为此处返回的结果应该是 "<" ,但返回的结果让我们很是意外
这里就需要注意了:我们会认为第一个返回结果是3,第二个返回结果是6,3-6=-3,不是小于零吗;这里我们就需要返回strlen函数本身了。
strlen函数的函数类型是 size_t ,而我们转到 size_t 的定义
我们会发现,它其实返回的是一个无符号的整型,所以上面那段程序返回 的其实是-3的无符号整数型,返回的是一个正数,所以才会输出">"。
(3)strlen的模拟实现
size_t my_strlen(const char* str) //使用const让目标字符串内容不可变吧,增加程序健壮性
{
assert(str); //此处加上断言,如若str是空指针,则直接停止程序,并打印错误信息
const char* star=str;
const char* end=str;
while (*end != '\0')
{
end++;
}
return end - star;
}
int main()
{
printf("%u",my_strlen("adfsdf"));
return 0;
}
结果:
二.长度不受限制的字符串函数 strcpy strcat strcmp
1.strcpy
(1)strcpy的使用
strcpy用于字符串的拷贝。需要传入俩个地址,一个是目标空间的首地址,一个是源字符串的首地址。在拷贝的过程中,strcpy以源字符串中的"\0"作为拷贝的结束标志。并且同样会将"\0"一同拷贝到目标空间。
int main()
{
char arr[10] = "xxxxxxxxx";
char arr2[] = { 'a','b','\0','c' };
strcpy(arr,arr2);
printf("%s",arr);
return 0;
}
(2)strcpy使用时的注意事项
1.目标空间必须要足够大,足够能容下源字符串。
如果目标空间不足以容下源字符串,如下代码:
//错误示范
int main()
{
char arr[2] = {0};
char arr2[] = "abcdefg";
strcpy(arr,arr2);
printf("%s",arr);
return 0;
}
2.目标空间必须是可变化的,如下代码:
//错误示范
int main()
{
char* p = "hello world";//常量字符串
char arr2[] = "abcdef";
strcpy(p, arr2);
printf("%s\n", p);
return 0;
}
(3)模拟实现strcpy
char* my_strcpy(char* dest, const char* source)
{
assert(dest);
assert(source);
char* ret = dest;
while (*dest++=*source++)
{
;
}
return ret;
}
int main()
{
char arr[20] = { 0 };
char arr2[] = "davadvasdv";
printf("%s",my_strcpy(arr,arr2));
return 0;
}
结果:
2. strcat
(1)strcat的使用
strcat函数用于在目标字符串后追加源字符串。在目标字符串中找到"\0"后将源字符串追加在后面,以源字符串的"\0"作为结束标志。
int main()
{
char arr[8] = "arc";
char arr1[] = "arrr";
printf("%s",strcat(arr,arr1));//以arr1的"\0"作为结束标志,并且会将arr中的"\0"替换掉
}
//这里返回arrarrr
为了测试是否是以"\0"未结束标志,可以调试下面的代码:
int main()
{
char arr[8] = "arc";
char arr1[] = "arr\0r";
printf("%s",strcat(arr,arr1));
}
调试后结果如下:
(2)strcat使用时的注意事项
1.源字符串必须以"\0"作为结尾。如若结尾不是"\0",就会继续往内存中寻找"\0",直到找到为止。
//错误示范
int main()
{
char arr[8] = "arc";
char arr1[] = {'a','b','c'}; //这里没有"\0",我们看看调试后的结果
printf("%s",strcat(arr,arr1));
}
2.目标空间必须足够大,能够容下俩个字符串的内容。
//错误示范
int main()
{
char arr[4] = "arc";
char arr1[] = "asdasd";
printf("%s",strcat(arr,arr1));
return 0;
}
3.目标空间必须可以变化的(可参考strcpy使用注意事项第二点)
4.strcat函数不可以自己追加自己,再追加自己的时候会将自己的"\0"覆盖掉,从而无限的追加下去,引发异常。
//错误示范
int main()
{
char arr[4] = "arc";
printf("%s",strcat(arr,arr));
return 0;
}
(3)模拟实现strcat
char* my_strcat(char* dest,const char* source)
{
assert(dest);
assert(source);
char* ret = dest;
while (*dest)
{
dest++;
}
while(*dest++=*source++)
{
;
}
return ret;
}
int main()
{
char arr[10] = "abc";
char arr1[] = "def";
printf("%s", my_strcat(arr, arr1));
return 0;
}
3. strcmp
(1)strcmp的使用
strmp函数较为简单,知道怎么使用就可以了,基本上不会出错。
int main()
{
char arr1[] = "abc"; //比较的是对应字符的ascii码值的大小
char arr2[] = "abf";
if (strcmp(arr1,arr2) < 0)
printf("arr1<arr2\n");
else if (strcmp(arr1, arr2) > 0)
printf("arr1>arr2\n");
else
printf("arr1==arr2\n");
return 0;
}
(2)strcmp使用的注意事项
需要注意的就是俩个字符串要有结束标志"\0",具体可以参考上面介绍的函数。在这里就不做过多的赘述了。
(3)strcmp的模拟实现
int my_strcmp(const char* s1, const char* s2)
{
assert(s1);
assert(s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
{
return 0;
}
s1++;
s2++;
}
return *s1 - *s2;
}
注:应如晦暗中斑斓,渺小却照彻河山。