函数原型:
作用:求字符串长度(第一个字符到第一个'\0'的字符数,不包括'\0'
实现:
size_t my_strlen(char*s)
{
size_t count = 0;
while (*s++)
{
count++;
}
return count;
}
这里的实现较为简单,不作赘述,库函数strlen实现方法与上述相同。
对于初学者来说可能会不理解size_t是什么类型
我们在vs中选中size_t类型,右击鼠标,点击转到定义
本质上编译器内部对这种类型进行了处理,size_t本质就是无符号整形,这种类型通常被用来表示大小或数量
函数原型:
作用:将source字符串(从第一个字符到第一个'\0',包括'\0')拷贝到destination字符数组
(注:const修饰了第二个参数,说明可以将字符串常量传递给函数,如果传入的是数组名,const char*类型也能够接收,而第一个参数必须是字符数组名,字符串常量不能修改)
函数实现:
char* my_strcpy(char *dest,const char*sour)
{
char* ret = dest;
while (*dest++ = *sour++);
return ret;
}
代码的道理也很简单,不做赘述
函数原型:
作用:从两个字符串的第一个字符依次往后比较,当碰到第一个不同的字符时,如果str1此字符的ASCII码比str2此字符的ASCII码大,函数返回大于0的值,反之则返回小于0的值,值不定,只是部分编译器规定了返回1和-1。如果两个字符串第一个'\0'前的所有字符均相同,函数返回0。
函数实现:;
int my_strcmp(const char*s1,const char*s2)
{
while (*s1 == *s2)
{
if (*s1 == 0)
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
函数原型;
作用:取消destination第一个'\0',从原来'\0'的位置将source字符串连接上来,包括source末尾的'\0'。
函数实现:
char*my_strcat(char *s1,const char*s2)
{
char* ret = s1;
while (*s1)
s1++;
while (*s1++ = *s2++);
return ret;
}
函数原型:
很明显,该函数比strncpy函数多了一个参数,这个参数规定了拷贝的字符数量
作用:如果source字符串字符数量少于num,那么就直接拷贝num个字符至destination起始位置;如果source字符串字符数量大于num,那么在source后面补'\0'至source有num个字符,再将num个字符拷贝至destination起始位置
函数实现;
char* my_strncpy(char* s1,const char* s2, size_t num)
{
char* ret = s1; //s1指针后面需要指向其他位置,故保留其实位置作返回值
size_t n = num - my_strlen(s2);//记录需要补齐的'\0'数量
if (my_strlen(s2) < num)
{
while (*s2)
{
*s1++ = *s2++;
}
while (n--)
{
*s1++ = 0;//补齐操作
}
}
else
{
while (num--)
{
*s1++ = *s2++;
}
}
return ret;
}
函数原型:
同样的,这里比strcat函数多了一个参数
作用:如果source字符串的字符数量大于num,那么将source中的前num个字符连接至destination,具体连接方法与strcat相同 ,末尾补上一个'\0';如果source字符串的字符数量小于num,那么直接将source拷贝至destination末尾,此时与strcat函数作用相同
char* my_strncat(char* s1, char* s2, size_t num)
{
char* ret = s1;
while (*s1)
s1++;
if (my_strlen(s2) <= num)
{
while (*s1++ = *s2++);//连同'\0'直接拷贝
}
else
{
while (num--)
{
*s1++ = *s2++;
}
*s1 = 0;//末尾补上'\0'
}
return ret;
}
函数原型:
函数的第一个参数和返回值可变,但是意义不大,在使用的过程中只要传入的是指针类型或者常量字符串都不会有问题,函数不会在内部修改指针指向的内存空间,可以放心传参
作用:在str1中找到和str2一样的子字符串,并返回第一个满足条件的子字符串的首元素地址
函数实现:
char* my_strstr(char* s1, char* s2)
{
size_t n = my_strlen(s1) - my_strlen(s2)+1;//计算比较次数
while (n--)
{
int flag = 1;
for (size_t i = 0; i < my_strlen(s2); i++)//每次比较都从s1的位置向后比较s2长度个字符
{
if (s1[i] != s2[i])
{
flag = 0;//如果有不同字符,就不满足条件
break;
}
}
if (flag == 1)
{
return s1;//如果每个字符都相同flag就不会改变,满足条件直接返回
}
s1++;//从下个位置开始比较
}
return NULL;//没找到,返回空指针
}
这里实现的方法的复杂度较高,和库函数自身的实现差不多。
假设s1的长度是4,s2的长度是3,那么需要比较2次
假设s1的长度是5,s2的长度是3,那么需要比较3次
依次类推,比较次数=s1长度-s2长度+1
提前计算好比较次数可以避免s1即将到达末尾时候的特殊判断,减小思维量
对于子字符串的问题,有KMP算法可以很好的解决,但是这种算法实现起来较为复杂,后续会深入探讨