目录
1.模拟实现strlen
注意:
size_t strlen ( const char * str );
1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )。
2.参数指向的字符串必须要以 ‘\0’ 结束。
3.注意函数的返回值为size_t,是无符号的
模拟实现:
#include<stdio.h>
size_t My_strlen(const char* str)//求字符串长度不需要更改原字符串,const修饰更安全
{
assert(str);//保证指针有效性
int count = 0;
while (*str++)
{
count++;
}
return count;
}
int main()
{
char str[] = { "abcdef" };
printf("len = %u",My_strlen(str));
return 0;
}
递归模拟实现:
size_t My_strlen(const char* str)
{
assert(str);
if (*str == '\0')
{
return 0;
}
return 1 + My_strlen(++str);
}
int main()
{
char str[] = { "abcdef" };
printf("len = %d\n",My_strlen(str));
return 0;
}
2.模拟实现strcpy
注意:
char* strcpy(char * destination, const char * source );
1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4目标空间必须可变。
模拟实现:
char* My_strcpy(char* dest, const char* scr)//字符串拷贝不需要更改源字符串,const修饰更安全
{
assert(dest && scr);//保证指针有效性
char* _dest = dest;
while (*dest++ = *scr++)
{
;
}
return _dest;
}
int main()
{
char dest[] = { "hello" };
char scr[] = { "world" };
printf("%s", My_strcpy(dest, scr));
return 0;
}
3.模拟实现strncpy
模拟实现:
char* My_strncpy(char* dest, const char* src, size_t sz)
{
assert(dest && src);//保证指针有效性
char* ret = dest;
while (sz--)
{
*dest++ = *src++;
}
*dest = '\0';//strncpy的特性,覆盖后结尾加上\0
return ret;
}
int main()
{
char str1[] = { "abcdef" };
char str2[7] = { 0 };
printf("%s\n",My_strncpy(str2, str1, 3));
return 0;
}
4.模拟实现strcat
注意:
char * strcat ( char * destination, const char * source );
1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
模拟实现:
char* my_strcat(char* arr,const char* cat)
{
assert(arr && cat);//保证指针有效性
char* tmp = arr;
//while (*arr++)不能这样写,因为到\0时出循环后还会++,跳过\0
//{
// ;
//}
while (*arr != '\0')//先找到尾部,再追加
{
arr++;
}
while (*arr++ = *cat++)
{
;
}
return tmp;
}
int main()
{
char arr[10] = { "abc" };
my_strcat(arr, "def");
printf("%s", arr);
return 0;
}
5.模拟实现strncat
模拟实现:
char* My_strncat(char* dest, const char* src, size_t sz)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (sz--)
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
int main()
{
char str1[15] = { "hello " };
printf("%s",My_strncat(str1, "painoworld", 5));
return 0;
}
6.模拟实现strcmp
注意:
int strcmp ( const char * str1, const char * str2 );
1.第一个字符串大于第二个字符串,则返回大于0的数字
2.第一个字符串等于第二个字符串,则返回0
3.第一个字符串小于第二个字符串,则返回小于0的数字
模拟实现:
int My_strcmp(const char* arr1,const char* arr2)
{
assert(arr1 && arr2);//保证指针有效性
while (*arr1 == *arr2)
{
if (*arr1 == '\0')//同时为\0的情况,其他时候若有一方为\0就会在while()判断里跳出循环
{
break;
}
arr1++;
arr2++;
}
return *arr1 - *arr2;//直接通过相减的方式判断大小更加简便
}
//为也可以这样写
int My_strcmp(const char* arr1, const char* arr2)
{
assert(arr1 && arr2);//保证指针有效性
while (*arr1 == *arr2 && *arr1)
{
arr1++;
arr2++;
}
return *arr1 - *arr2;//直接通过相减的方式判断大小更加简便
}
int main()
{
char arr1[] = { "abcdz" };
char arr2[] = { "abcda" };
int ret = My_strcmp(arr1, arr2);
if (ret == 0)
{
printf("==\n");
}
else if (ret > 0)
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
7.模拟实现strncmp
模拟实现:
int My_strncmp(const char* str1, const char* str2, size_t sz)
{
assert(str1 && str2);
while (*str1 == *str2 && sz != 1)
{
sz--;
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
char str1[] = { "hello" };
char str2[] = { "hel" };
int ret = My_strncmp(str1, str2, 3);
if (ret == 0)
{
printf("==");
}
else if(ret > 0)
{
printf(">");
}
else
{
printf("<");
}
return 0;
}
8.模拟实现strstr
注意:
char * strstr ( const char *str1, const char * str2);
1.如果 str2 不是str1返回指向 str1 中第一次出现的 str2 的指针。
模拟实现:
char* My_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);//保证指针有效性
const char* s1 = str1; //记录起始位置
const char* s2 = str2;
const char* p = str1; //图文解释
while (*p) //检测p是否为\0,如果是,说明已经找完母串,却未发现字串
{
s1 = p;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')//如果字串已经遍历到\0,说明找完了,并且找到了,此时p所指向的就是与子串开始匹配的地址
{
return p;
}
p++;
}
return NULL;
}
int main()
{
char str1[] = "abbbcdef";
char str2[] = "bbc";
char* p = My_strstr(str1, str2);
if (p == NULL)
{
printf("找不到\n");
}
else
{
printf("找到了\n");
}
return 0;
}
此函数模拟稍有难度,可以看下图解释:
情况一:
这里通过循环判断s1 == s2就可一次得出判断结果
情况二 :
第一次相遇:
第二次相遇:
第三次相遇:
此时*s1 = b; *s2 = c; 所以证明不是字串。
真的是这样吗?
仔细观察,bbc确实是他的字串啊!
但是根据情况一,只靠循环一股脑的遍历下去是不行的…
因此再引入一个指针变量p来记录位置就十分有必要了
当*s1与s2*第一次相等是就用p指针记录下来,如果s1与s2继续向后比较,发现不匹配了难道要继续向后走吗?当然行不通的,像这种bbc情况就会错过这对有缘人啊~ 这时,我们只需让s1继续回到刚刚指针p记录的位置的下一个位置,让s2回到起始位置,继续相互比较即可。
9.模拟实现strtok
注意:
char * strtok ( char * str, const char * sep );
1.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
2.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
3.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
4.如果字符串中不存在更多的标记,则返回 NULL 指针。
模拟实现:
char* My_strtok(char* str, const char* sep)
{
assert(sep);//保证指针有效性
char* s1 = NULL;//记录初地址
static char* p = NULL;//记录字符串位置
static int count = 0;//记录分隔符位置
if (str == NULL)
{
count++;
p++;
}
else
{
p = str;
}
s1 = p;//记录每次传入子串的初始地址
while (*p != *(sep + count) && *p != '\0' && (sep + count) != '\0')
{
p++;
}
if (*p == *(sep + count))//如果与分隔符相等,则置为\0,并返回s1
{
*p = '\0';
return s1;
}
else
{
return NULL;
}
}
int main()
{
const char* sep = "@.";//分隔符
char email[] = { "chenyikang@gitee.com" };//待被分割的对象
char tmp[30] = { 0 };//strtok会修改原串,每分割一次会将原串中的分隔符改为\0,所以创造了这个零时字符串
strcpy(tmp, email);
char* ret = NULL;
for (ret = My_strtok(tmp, sep);
ret != NULL;
ret = My_strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
10.模拟实现memcpy
注意:
void * memcpy ( void * destination, const void * source, size_t num );
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的。
模拟实现:
void* My_memcpy(void* dest, const void* scr, size_t sz)
{
assert(dest && scr);//保证指针有效性
int ret = dest;
while(sz--)
{ //由于传入的是字节数,所以只需要强制类型转化成char*类型,
//解引用后为char类型一个一个字节覆盖就okk
*(char*)dest = *(char*)scr;
((char*)dest)++;
((char*)scr)++;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
My_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
11.模拟实现memmove
注意:
void * memmove ( void* destination, const void * source, size_t num );
模拟实现:
void* My_memmove(void* dest, const void* src, size_t sz)
{
assert(dest && src);//保证指针有效性
int ret = dest;
//有时需要从前往后处理,有时需要从后往前处理,不能直接认为从后往前覆盖解决一切问题!
//当dest 再 src 左边,需要从前向后
if (dest < src)
{//前->后
while (sz--)
{
*(char*)dest = *(char*)src;
((char*)dest)++;
((char*)src)++;
}
}
else
{//后->前
while (sz--)
{
*((char*)dest + sz) = *((char*)src + sz);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
My_memmove(arr1+2, arr1, 12);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
12.模拟实现memcmp
注意:
int memcmp ( const void * str1, const void * str2, size_t num );
模拟实现:
int My_memcmp(const int* arr1, const int* arr2, size_t sz)
{
assert(arr1 && arr2);
while (*(char*)arr1 == *(char*)arr2 && sz != 1)
{
sz--;
((char*)arr1)++;
((char*)arr2)++;
}
return (*(char*)arr1 - *(char*)arr2);
}
int main()
{
int arr1[] = { 1,2,3,4,5,6 };
int arr2[] = { 1,3,3};
int ret = My_memcmp(arr1, arr2, 12);
if (ret == 0)
{
printf("==");
}
else if(ret > 0)
{
printf(">");
}
else
{
printf("<");
}
return 0;
}
13.模拟实现memset
注意:
void* memset(void* ptr, int value, size_t sz)
模拟实现:
void* My_memset(void* ptr, int value, size_t sz)
{
assert(ptr);
void* ret = ptr;
while (sz--)
{
*((char*)ptr) = value;
((char*)ptr)++;
}
return ptr;
}
int main()
{
char str[] = { "hello world" };
My_memset(str, 'x', 5);
printf("%s", str);
return 0;
}
码字不易~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129916.html