字符串拷贝的函数模拟实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strcpy(char*dest,const char*scr)//const表示指针指向的源字符串不能被改变
{
char* ret = dest;
assert(dest != NULL);//断言
assert(scr != NULL);
while(*dest++ = *scr++)
{
;
}
return ret;//返回目标字符串的第一个地址
}
int main()
{
char arr1[20] = "hello world!";
char arr2[] = "************";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
程序的运行结果为: hello world!
这个字符串拷贝函数是我自己定义的一个函数,叫做my_strcpy函数。
my_strcpy函数的返回值类型是char*,即返回一个地址,有两个参数,一个
是目标拷贝字符串的地址,一个是不能被改变的源字符串的内容的地址。
Debug版本中assert断言的作用是告诉程序员错误出现在哪里,而在release版本,assert又会被优化掉。
在while循环中,源字符串的内容拷贝到目标字符串之后,指针指向下一个字符的地址,继续进行拷贝过程,当指针指向’\0’时,源字符串中的’\0’拷贝到目标字符串,这时*dest==0,循环结束,’\0’也被拷到目标字符串里。
这样,hello world!就被完全拷贝到了arr2里,在主函数里调用这个函数,最终程序结果就是上述结果。
while(*scr++==*dest++)
如果代码如上所示,在第二个参数前加上const,这一条语句就无法正确编译。
字符串函数模拟实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
int my_strlen(char*str)//返回值为整型,也可以是size_t,表示无符号的整型
{
int count = 0;
assert(str != NULL);//断言
while (*str++ != '\0')
{
count++;
}
return count;
}
int main()
{
int len = my_strlen("abcd");
printf("%d\n", len);
return 0;
}
程序的执行结果为:4。
同样,我自己定义了my_strlen的函数,来模拟实现库函数里的strlen函数。
my_strlen函数返回一个整型,参数传的是一个字符串str不能被改变的的地址。
定义一个计时器count,断言字符指针str不为空指针,while循环中*str !==’\0’代表字符串中的字符不为\0,计数器加一,然后指针向后移动一位,指向下一个字符,
直到字符串中的字符等于\0,循环结束,返回计数器个数。
在主函数中,调用my_strlen函数,将这个值放在定义的len变量中,最终的程序结果也为上述结果。
字符串追加函数的模拟实现
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
//1. 找目标空间的'\0'
while(*dest)
{
dest++;
}
//2. 追加
while(*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
my_strcat(arr1, arr1);
printf("%s\n", arr1);
return 0;
}
以此类推,定义my_strcat函数,它的返回值、参数和my_strcpy函数一样。
断言的作用也是相同的,第一个while循环判断*dest是否为’\0’,当循环到’*dest ==\0’时,循环停止,执行下一个while循环,它的作用和my_strcpy函数的作用一样,在上一个’\0’后面开始拷贝字符串。
字符串追加函数要注意5点:
1.目标字符串中必须有’\0’
2.源字符串中必须有’\0’
3.目标字符串必须可修改
4.目标空间必须足够大
5.自己不能给自己追加
字符串比较函数的模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while(*str1 == *str2)
{
if(*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1-*str2;
}
int main()
{
char* str1 = "abc";
char* str2 = "abcdef";
int ret = my_strcmp(str1, str2);
printf("%d\n", ret);
return 0;
}
定义my_strcmp函数,参数都是不能改变的字符串的地址,返回值是大于0,小于0或者等于0的值。
先断言指针是否指向空的地址,再进入while循环中,判断两个字符串中的字符从左往右是否相等,如果两个字符串内的字符都是’\0’,则直接返回0。
return str1-str2的含义为,当str1大于str2时,返回一个正数;当str1小于str2时,返回一个负数;当*str1等于 *str2时,返回0。
在字符串查找字符串函数的模拟实现
char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = str1;
const char* s2 = str2;
const char* pstart = str1;
assert(str1 != NULL);
assert(str2 != NULL);
//查找
if(*str2 == '\0')
return (char*)str1;
while(*pstart)
{
s2 = str2;
s1 = pstart;
while(*s1 && *s2 && *s1==*s2)
{
s1++;
s2++;
}
if(*s2 == '\0')
{
return (char*)pstart;
}
pstart++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if(ret == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
定义my_strstr函数,返回值为char*,参数为字符串不可变的两个字符串的地址.
在逻辑分析前,定义三个char*类型的指针,分别为s1,s2,pstart.将str1的首地址赋给 s1 和start,把str2的地址赋给s2.
进行断言,判断指针变量str1和str2是否为空指针,判断如果str2是一个空字符串, 直接返回str1.当*start不为’\0’时进入第一个循环,str2的首地址给s2,start的首地址给s1.
进入第二个循环,当s1,s2不等于’\0’且s2等于s1时,指针s1,s2向右移动一位. 当循环跳出来时,*s2如果等于’\0’,则说明字符串str2已经被找完,返回指针变量pstart.
如果s2不等于s1时,且*s2 != '\0’时,循环跳出,这时start向后移动一位,将指针pstart指向的地址给s1.
将指针str2指向的地址重新给s2,这样指针s2又重新指向str2字符串的第一个字符,重新开始查找.如果*pstart==’\0’,则返回NULL.
在主函数中,定义一个指针变量ret,将函数的地址赋给ret,则如果ret==NULL,说明不存在,否则,,如上面的代码返回字符串bbcdef。