系列文章目录
字符函数和字符串函数详解(一)strlen strcpy strcat strcmp
字符函数和字符串函数详解(二)strncpy strncat strncmp strstr strtok(及其模拟实现)
字符函数和字符串函数详解(三)strerror memcpy memmove memset memcmp(及部分字符分类函数)
目录
一.求字符串长度的函数strlen
1.strlen
(1)strlen的使用
(2)strlen使用时的注意事项
(3)strlen的模拟实现
二.长度不受限制的字符串函数 strcpy strcat strcmp
1.strcpy
(1)strcpy的使用
(2)strcpy使用时的注意事项
(3)模拟实现strcpy
2. strcat
(1)strcat的使用
(2)strcat使用时的注意事项
(3)模拟实现strcat
3. strcmp
(1)strcmp的使用
(2)strcmp使用的注意事项
(3)strcmp的模拟实现
这一系列专门做c语言中的字符和字符串函数的使用教程,和常遇见的相关错误的原因和规避错误要注意的要点。(第一期:strlen strcpy strcat strcmp)
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
}
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的无符号整数型,返回的是一个正数,所以才会输出">"。
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用于字符串的拷贝。需要传入俩个地址,一个是目标空间的首地址,一个是源字符串的首地址。在拷贝的过程中,strcpy以源字符串中的"\0"作为拷贝的结束标志。并且同样会将"\0"一同拷贝到目标空间。
int main()
{
char arr[10] = "xxxxxxxxx";
char arr2[] = { 'a','b','\0','c' };
strcpy(arr,arr2);
printf("%s",arr);
return 0;
}
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;
}
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;
}
结果:
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));
}
调试后结果如下:
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;
}
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;
}
strmp函数较为简单,知道怎么使用就可以了,基本上不会出错。
int main()
{
char arr1[] = "abc"; //比较的是对应字符的ascii码值的大小
char arr2[] = "abf";
if (strcmp(arr1,arr2) < 0)
printf("arr1 0)
printf("arr1>arr2\n");
else
printf("arr1==arr2\n");
return 0;
}
需要注意的就是俩个字符串要有结束标志"\0",具体可以参考上面介绍的函数。在这里就不做过多的赘述了。
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;
}
注:应如晦暗中斑斓,渺小却照彻河山。