目录
前言
在上一篇博客中博主详细的讲解了各字符串函数的使用,包括参数,返回值类型,应用场景等,但是有的场景或是题目中要求我们不能使用某一个特定的库函数,或是直接要求我们模拟实现这个库函数。这个时候仅仅学会这些函数的使用就不够用了。今天我们就来讲讲各字
符串函数以及内存函数的模式实现。
字符串函数的模拟与实现
1.strlen函数的模拟实现
strlen的函数声明:
size_t strlen ( const char * str );
strlen函数其功能是求字符串长度,参数是字符串的首地址,返回值是字符串长度。字符串的长度由结束的空字符(\0)决定:字符串的长度等于字符串开头和结束的空字符之间的字符数(不包括结束的空字符本身)。
1)计数器模拟实现strlen函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
size_t my_strlen(const char* p)
{
assert(p);
int count = 0;
while (*p)
{
count++;
p++;
}
return count;
}
int main()
{
char arr[] = "ABCDEFGH";
printf("%d\n",my_strlen(arr));
return 0;
}
size_t是无符号整形数据,const可以防止*p被改变,增强了代码的鲁棒性或健壮性。assert是断言,当传参传的是一个空指针时,assert就会报错,这样我们就可以及时修正代码。如图
2)指针法模拟实现strlen函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
size_t my_strlen(const char* p)
{
assert(p);
char* tmp = p;
while (*p != '\0')
{
p++;
}
return p - tmp;
}
int main()
{
char arr[] = "ABCDEFGH";
printf("%d\n",my_strlen(arr));
return 0;
}
指针减指针求得两指针之间的元素个数,tmp用于记录数组的起始位置。
3)递归法模拟实现strlen函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
size_t my_strlen(const char* p)
{
assert(p);
if (*p == '\0')
{
return 0;
}
else
{
return 1 + my_strlen(p + 1);
}
}
int main()
{
char arr[] = "ABCDEFGH";
printf("%d\n",my_strlen(arr));
return 0;
}
2.strcpy函数的模拟实现
strcpy的函数声明:
char * strcpy ( char * destination, const char * source );
strcpy函数用于复制字符串,简单来说就是将一个字符数组中的字符串复制到另一个字符数组中。其函数声明中destination目标字符串的指针,source是源字符数组的指针,即把source里的内容复制到destnation里。其返回值是一个字符型指针,返回的是目标字符串的起始地址。
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[100] = "abcdef";
char arr2[] = "qwertyuiop";
printf("%s\n",my_strcpy(arr1, arr2));
return 0;
}
因为是从源字符数组中复制到目标字符数组中,所以目标字符数组的内容会被改变,因此其指针前不能加const修饰,而源字符数组中的内容不用改变,加上const可以增强代码的健壮性。
3.strcmp函数的模拟实现
strcmp函数的声明:
int strcmp ( const char * str1, const char * str2 );
strcmp函数主要用于比较两个字符串的大小,其实字符串函数在比较字符串大小时是比较相同位置上字符的ASCII值的大小,我们知道字符在内存中存放的都是各字符对应的ASCII值,当strcmp函数在某一个位置上比较出字符大小后就会停止比较,返回一个有符号数值,即大于0返回一个大于0的数,小于0返回一个小于0的数。当然,当比较了所有位置后,各个位置都相等,那么此时两个字符串相同,函数返回0。值得一说的是,虽然strcmp函数比较的是字符的ASCII值,但是计算机中都是以二进制补码存放数据,所以归根结底,是在比较字符在内存中的二进制数。
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 && *str2 && *str1 == *str2)
{
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "abcdefg";
char arr2[] = "abcdefgh";
int ret = my_strcmp(arr1, arr2);
if (ret == 0)
{
printf("==\n");
}
else if (ret < 0)
{
printf("<\n");
}
else
{
printf(">\n");
}
return 0;
}
4.strcat函数的模拟实现
strcat函数的声明:
char* strcat(char* destination, const char* source);
strcat函数用于连接字符串,将源字符串的副本追加到目标字符串。目标字符串的中的结束字符\0会被源字符串的第一个字符覆盖,并且在目标字符串中由两者串联形成的新字符串的末尾包含一个空字符。strcat函数会返回目标字符串的起始地址。
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);
char* ret = str1;
while (*str1)
{
str1++;
}
while (*str1++ = *str2++)
{
;
}
return ret;
}
int main()
{
char arr1[50] = "I miss you";
char arr2[] = " very much!";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
注意:这种实现方法是有缺陷的,当字符串数组自己拼接自己时,程序会崩溃,\0会被覆盖掉,导致死循环。
如果一定要字符串自己拼接自己,那么最好还是使用strncat函数,如下:
char * strncat ( char * destination, const char * source, size_t num );
(num是要追加的字符个数)
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
strncat(arr1, arr1, 6);
printf("%s\n", arr1);
return 0;
}
5.strtok函数的模拟实现
strtok函数是字符串分割函数,它有两个参数,具体细节如下:
注意:上述说的标记也就是分隔符
看了上面的解释还不明白的小伙伴可以去看看博主的上一篇博客,里面详细的讲解了各字符串函数的使用和解析。 链接在此: http://t.csdn.cn/2vL2U
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strtok(char* buf1, const char* buf2)
{
assert(buf2);
char* ret = NULL;//记录分隔符前一句字符的第一个字符地址(作为返回值)
static char* s1 = NULL;//记录分隔符后一个字符的地址
ret = buf1;
if (buf1 == NULL && s1 == NULL)
{
return NULL;
}
if (buf1 == NULL)
{
buf1 = s1;
ret = s1;
while (*buf1)
{
for (int i = 0; i < strlen(buf2); i++)
{
if (*buf1 == *(buf2 + i))
{
*buf1 = '\0';
s1 = buf1 + 1;
return ret;
}
}
buf1++;
}
s1 = NULL;
return ret;
}
else
{
while (*buf1)
{
for (int i = 0; i < strlen(buf2); i++)
{
if (*buf1 == *(buf2 + i))
{
*buf1 = '\0';
s1 = buf1 + 1;
return ret;
}
}
buf1++;
}
s1 = NULL;
return ret;
}
}
int main()
{
char arr[] = "money$1234?Mr.Tang@young?man#litan";
char str[100] = { 0 };
char sep[] = "$.@?#";//分隔符是自己定义的,C语言中并没有确切的规定分隔符有哪些
strcpy(str, arr);
char* ret = NULL;
//strtok(str,sep)只找第一个分隔符并返回该分隔符前的一段字符的第一个字符的地址
//strtok(NULL,sep)从保存好的位置继续往后找分隔符
//找到分隔符后strtok函数会将其赋值为\0,并保存该地址
for (ret = my_strtok(str, sep); ret != NULL; ret = my_strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
6.strstr函数的模拟实现
strstr函数的声明:
const char* strstr(const char* str1, const char* str2);
strstr函数是子串查找函数,其功能是从主串中查找子串,例如在“qwertyabcdefuiorwe”这个主串中查找“abcdef”这个子串。其两个参数分别为主串和子串的首字符地址。返回值为指向子串中指定的整个字符序列在主串中第一次出现的指针,如果该序列不存在于主串中,则返回空指针。在该例子中也就是返回“qwertyabcdefuiorwe”主串中a的地址,若该主串中没有abcdef这个序列,则返回空指针NULL。
#include<stdio.h>
#include<string.h>
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* s2 = str2;
const char* cur = str1;
while (*cur)
{
s1 = cur;
s2 = str2;
while (*s1 && *s2 && (* s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cur;
}
cur++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdefgabcdejh";
char arr2[] = "abcdef";
printf("%s\n", my_strstr(arr1, arr2));
return 0;
}
本篇以字符串函数的模拟实现为主题的博客到此就要结束了,希望本篇博客可以帮助到各位小伙伴,博主码字不易,如果本篇博客对你有所帮助,还望各位小伙伴点赞👍,收藏⭐+关注,感谢各位的支持!如果有什么不明白的地方或是另有其他的高见,也可以在评论区留言,博主也会及时回复或进行更改,欢迎指正,谢谢!