目录
前言
一、函数介绍
1.strlen
2.strcmp
3.strcat
总结!!!!!!!
4.strcpy
5.长度受限的字符串函数
二、函数模拟实现
1.strlen的模拟实现
2.strcpy的模拟实现
3.strcmp的模拟实现
5.strstr
总结
C语言中,我们经常要对字符串操作,因此我们要了解和掌握各种字符和字符串函数,以下带来部分C语言库中自带的几个函数。
strlen()函数对与我们来说并不陌生,它用来计算一个字符串的长度的,它的规则是,从字符串首元素开始往后查找,直到找到’\0',这之间的元素个数就是strlen()函数的返回值。
我们发现在库函数中strlen()返回值的类型是size_t,size——t的本质是无符号整型。这是我们就要注意,有可能会引起一些错误
例
#include
#include
int main()
{
const char* arr1 = "Hello World";
const char* arr2 = "你好 世界";
if (strlen(arr2) - strlen(arr1) > 0)
printf("arr2>arr1");
else
printf("arr2<=arr1");
return 0;
}
我们看这段代码,我们可能会不假思索就回答出屏幕上会打印出arr2<=arr1,但是结果是出乎意料
打印出来的结果与我们的想法是相反的。 根据我们的观察arr1数组的长度为12,arr2函数的长度是10,它们两个相减得到的是-2,恰好是小于零的整型,-2的源码是10000000000000000000000000000010反码是11111111111111111111111111111101补码是11111111111111111111111111111110。但是strlen()返回的是size_t是无符号整型,没有符号位直接转化为十进制数是4294967293这一定是大于0的数,结果就算出了,arr2>arr1
我们可以这样修改代码,来实现代码原本的功能
#include
#include
int main()
{
const char* arr1 = "Hello World";
const char* arr2 = "你好 世界";
if (strlen(arr2)>strlen(arr1))
printf("arr2>arr1");
else
printf("arr2<=arr1");
return 0;
}
我们通常会把strlen()和C语言关键字sizeof()混淆,sizeof()是计算类型在内存中所占的字节大小,换到数组的定义来说,数组的类型是去掉数组名剩下的部分,所以它能算出数组在内存中所占内存的大小,它计算出的数组大小包含数组隐藏的'\0',我们可以用整个数组的大小除以数组中一个元素的大小,来计算数组元素的个数。sizeof()只计算在内存中所占字节大小,不会寻找'\0'。
我们或许对这个函数会比较陌生,我们根据strcmp字面意义上的理解,它是用来比较两个字符串的,但是是比较两个字符串的什么,我们会比较疑惑,其实strcmp()比较的不是字符串长度,比较的是字符串中对应位置上的字符大小,如果相同就比较下一对,直到其中一个字符串到末尾及找到'\0'。
它的返回值是int型,如果返回一个大于0的数,代表string1大于string2,返回0代表string1等于string2,返回小于0代表string1小于string2。
例
#include
#include
int main()
{
char arr1[] = "hello world";
char arr2[] = "werrcxzawd";
if (strcmp(arr1, arr2) > 0)
{
printf("arr1>arr2\n");
}
else if (strcmp(arr1, arr2) == 0)
{
printf("arr1==arr2\n");
}
else
{
printf("arr1
这个函数就十分有意思了,它是用来将一个字符串追加到另一个字符串之后
我们要注意几点,strcat函数在destination字符串中是通过找'\0'来定位要添加的位置,所以destination字符串就必须要有'\0'像这种
char arr[] = { 'w','q','e','a' };
不完全初始化的字符串千万不能引用strcat函数,strcat函数会因为无法找到'\0'而使程序死掉。
同时它不能自己追加自己,strcat函数有一个比较有意思的细节,它追加时,源头字符串的首元素会覆盖掉destination字符串的'\0',就会导致strcat函数无法找到'\0'而崩溃。
如果我们定义了一个常量字符串,就会因为常量字符串无法被strcat修改而出现bug
还有destination必须足够大,如果没有提前预留出源头字符串的空间,虽然strcat函数会强行追加上,但是会出现警告和未知的风险
#include
#include
int main()
{
char arr1[] = "Hello";
char arr2[] = "qwffgfffsdsw";
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
虽然出现了错误,但是还是将arr1追加后的内容打印出来了。
strcpy()-----复制一个字符串
将源头字符串,复制进入目标字符串
它的具体细节是将这两个字符串的字符,一个一个的替换,直到将源头字符串的'\0'复制进入目标字符串结束。
我们要注意:源字符串必须以 '\0' 结束。会将源字符串中的 '\0' 拷贝到目标空间。 目标空间必须足够大,以确保能存放源字符串。 目标空间必须可变。
这些注意都是每一个字符串函数都要注意的。
strcmp strcat 和strcpy函数长度都是不受限制的字符串函数
以下介绍的是长度受限的字符串函数
这几个函数都是在原函数的基础上多加了一个参数n用来限制字符串函数操作的字节数
其中stncpy函数会在复制结束末尾在加上'\0'就相当于将字符串截断。
strncat函数虽然你指定它追加n个元素,但实际上会追加n+1个元素,它会自动的追加'\0'
但是这个函数的n如同fgets()函数的参数n一样,你如果实际的字符串长度小于n,剩下的用'\0'来补充。
#include
int my_strlen(char* arr)
{
int count = 0;
while (*arr++)
{
count++;
}
return count;
}
int main()
{
char arr[] = "Hello World";
printf("%d\n", my_strlen(arr));
return 0;
}
strlen()函数本质上是用来找'\0'这是第一种用指针来实现
下面是用递归实现
int my_strlen_recursion(char* arr)
{
if (*arr == '\0')
return 0;
else
{
return 1 + my_strlen_recursion(arr + 1);
}
}
int main()
{
char arr[] = "Hello World";
//printf("%d\n", my_strlen(arr));
printf("%d\n", my_strlen_recursion(arr));
return 0;
}
我们可以利用递归的思想,字符串arr的长度等于1+my_strlen_recursion(arr+1)来替换,相当于1加上arr字符串长度减1,我们大体的思路有了,但是要写出有效的递归程序,我们必须考虑递归的出口及达到什么条件递归才会终止,我们这个程序目的是算出字符串的长度,因此字符串结束的标准'\0'也为递归程序的出口。
char* my_strcpy(char* des, const char* src)
{
char* ret = des;
while (*des++ = *src++)
{
;
}
return ret;
}
strcpy函数在之前的文章中模拟实现过就不在赘述了。
#include
#include
int my_strcpy(const char* e1, const char* e2)
{
assert(e1 && e2);
return *e1 - *e2;
}
int main()
{
char arr1[] = "egfddssdfs";
char arr2[] = "dbhsjuhi";
if (my_strcpy(arr1, arr2) > 0)
{
printf("arr1>arr2");
}
else if (my_strcpy(arr1, arr2) == 0)
{
printf("arr1==arr2");
}
else
{
printf("arr1
这个函数还是比较有意思的,它是用来看一个字符串是不是另一个字符串的子串,它的返回类型是char *类型,如果不是另一个字符串的子串,它会返回NULL,如果是子串它会返回子串的起始地址。
你现在听我说可能会比较懵,现在上代码!!!!!!!!!!!!!!
#include
#include
int main()
{
char arr1[] = "abcdefghigk";
char arr2[] = "cdef";
if (strstr(arr1, arr2) == NULL)
{
printf("arr1不是arr2的子串\n");
}
else
{
printf("%s\n", strstr(arr1, arr2));
}
return 0;
}
接下来我们来模拟实现
#include
#include
#include
char* my_strstr(char* des, char* src)
{
assert(des && src);
const char* s1 = des;
const char* s2 = src;
const char* sur = des;
while (*sur)
{
s1 = sur;
s2 = src;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)sur;
sur++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdefghigk";
char arr2[] = "cdef";
/*if (strstr(arr1, arr2) == NULL)
{
printf("arr1不是arr2的子串\n");
}
else
{
printf("%s\n", strstr(arr1, arr2));
}*/
if (my_strstr(arr1, arr2) == NULL)
{
printf("arr1不是arr2的子串\n");
}
else
{
printf("%s", my_strstr(arr1, arr2));
}
return 0;
}
我们通过三个指针来控制,s1来控制主字符串,s2是用来控制子字符串的,sur是用来记录如果src是des子字符串的起始地址的。往复循环直到src字符串被遍历。