一、字符操作函数的模拟实现
strlen();strcpy(),strncpy();strcmp(),strncmp();strcat(),strncat();strstr()
//需要注意的地方有①不要忘记断言;②保留原字符串的起始地址,内存拷贝函数不存在这种情况
1.模拟实现strlen(),strlen()是用来求解字符串长度的函数,当遇到’\0’时停止计数,因此strlen()所求的字符串长度不包括’\0’的长度。
//1.1模拟实现strlen,计数器法模拟实现strlen()
int my_strlen1(const char* str)//const防止字符串被改变
{
assert(str != NULL);//断言,防止传入空指针,如果是空指针,会抛出异常,空指针不能进行解引用
int count = 0;
while(*str != '\0')//对字符串进行解引用,得到字符串里面的值然后与字符串的结尾标志'\0'进行比较
{
str++;
count++;
}
return count;
}
//1.2用指针减指针的方法模拟实现strlen
int my_strlen2(const char *str)
{
assert(str != NULL);
char *p = str;
while (*p != '\0')//同样,对指针进行解引用得到字符串里面的真实值然后与'\0'进行比较,知直到将p指针加到字符串的最后一个位置
{
p++;
}
return p - str;
}
//1.3、用函数递归的方法模拟实现strlen
int my_strlen3(const char *str)
{
assert(str != NULL);
if (*str == '\0')
return 0;
else
return 1 + strlen(str + 1);
}
2.模拟实现strcpy(),strncpy()
①strcpy()是一种c语言的标准库函数,把以src为起始地址切含有’\0’的字符串拷贝到以dest为起始地址的空间内,当遇到’\0’时,拷贝结束。模拟实现时,需要手动将’\0’拷贝进去。
②strncpy()解决了strcpy()的溢出问题,strcpy()只是一个字符串拷贝函数,对拷贝的字节数没有限制,strncpy()可以选择一段字符进行输出。
③一般情况下,使用strncpy()时,建议将n置为dest串长度,复制完毕后,为保险起见,将dest串最后一字符置NUL。
//2.1模拟实现strcpy()
char* my_strcpy(char *dest, const char *src)//为了保证源字符串不被改变,需要在定义字符串之前加上const修饰;在这里需要注意,目标字符串必须有足够大的空间
{
assert(dest != NULL&&src != NULL);
char * address = dest;//保存目标字符串的起始地址,为了从起始地址开始返回拷贝之后的字符串
while ((*dest++ = *src++))//后置++,先使用,后++,先把源字符串的第一个字符拷到目标字符串中,然后依次向后拷贝,最后再与'\0'进行比较,当指针走到'\0'时,while语句不成立,结束循环
{
;
}
*dest = '\0';//需要将'\0'也拷贝进去
return address;
}
//2.2模拟实现strncpy
//为了避免strcpy造成的溢出现象,可以考虑使用strncpy,srncpy是将源字符串src的n个字符复制到目标dest字符串当中,
//模拟实现strncpy要注意字符串中的'\0',因为它是将字符串中的n个字符拷贝到另一个字符串中,所以并不能确定是否将'\0'拷贝进去
char* my_strncpy(char *dest, const char *src, int n)
{
assert(dest!=NULL&&src!=NULL);
char *ret = dest;//保存原始字符串的地址,保存返回值
while (n)//拷贝n个字符串
{
*dest++ = *src++;
n--;
}
if ((*dest - 1) != '\0')//判断是否将'\0'拷贝进去
*dest = '\0';
return ret;
}
//3.1模拟实现strcmp(),strcmp()是一个字符串比较函数,s1==s2,返回0;s1
//s1>s2,返回正数,最终结果是返回二者的SASCII值之差
int my_strcmp1(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;//注意在这块对指针进行解引用,得到ASCII值相减的结果
}
3.模拟实现strcmp,strncmp这两个函数都是字符串比较函数,比较的结果是用相同位置上原字符串src上的字符所对应的ASCII减去目标字符串dest上的字符所对应的ASCII
//3.1模拟实现strcmp,strcmp是一个字符串比较函数,s1==s2,返回0;s1
//s1>s2,返回正数,最终结果是返回二者的SASCII值之差
int my_strcmp1(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;//注意在这块对指针进行解引用,得到ASCII值相减的结果
}
//3.2模拟实现strcmp
int my_strcmp2(const char *str1, const char *str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while ((*str1 == *str2) && (*str1 != '\0'))
{
str1++;
str2++;
}
return *str1 - *str2;
}
//3.3模拟实现strncmp(),strncmp()是比较两个字符串中前n个字符是否相等,只需要用while语句控制前n个字符即可
int my_strncmp(const char*dest, const char*src,int n)
{
assert(dest);
assert(src);
while (n--)
{
if(*dest == *src)//在这里要注意用if-else语句,不用的话就只将第一个字符进行了比较
{
dest++;
src++;
}
else
return *dest - *src;
}
}
4.模拟实现strcat(),strncat()这是一组字符串追加函数,strcat是将原字符串src追加到目标字符串dest的后面,二strncat是将源字符串src的n个字符追加到目标字符串dest的后面。
//4.1 模拟实现字符串追加函数strcat(),strcat()是一个字符串连接函数,是将字符串str2连接到字符串str1的后面,
//并覆盖str1后面的'\0'
char* my_strcat(char *dest, const char *src)
{
char *ret = dest;//保存原始字符串的起始地址
while (*dest != '\0')//在追加字符串之前,需要先把原字符串先便利一遍,找到原字符串的结尾,遍历到'\0'时,循环退出
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
//4.2模拟实现字符串追加函数strncat(),这里是指追加字符串的前n个字符
//用两个while循环,第一个用来遍历目标字符串,找到原字符串的最后一个指针,
//第二个字符串用来完成原字符串向目标字符串的赋值(要注意指针的动态增长)
//在这里要定义一个ret指针,用来记录目标字符串的起始位置,用来准确返回
char* my_strncat(char* dest, const char*src, int n)
{
assert(dest);
assert(src);
char *ret = dest;
while (*dest)
{
dest++;
}
while (n--)
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
5.模拟实现strstr(),这个函数用来判断你要查找的字符串是否在原有的字符串当中,如果有,返回字符串在原有字符串中的位置,如果没有,则返回空
函数实现的整体思路如下:
①设置两个指针str,substr,分别指向两个字符串的头部,然后对两个指针进行解引用
②比较两个解引用后的两个字符是否相等,如果不相等,str继续往后走,substr不动;
③当两个指针相等时,两个指针同时向后走。另外,要注意一种特殊情况:str:abbbcdef substr:bbcd,如果用上面的方法就会出现错误,因此当遇到两个指针不想等时,str需要返回到起始位置的下一个位置,所以这里需要设置一个cp指针记录起始位置,同时,也要让substr回到起始位置
下来用图来解释以下上面出现的两种情况:
第一种情况:在字符串”abcdef”中查找”bcd”,思路如下:
显然这种方法对于特殊情况是存在问题的,比如在字符串”abbbcdef”中查找”bbcd”,
char* my_strstr(const char* dest, const char *src)
{
assert(dest);
assert(src);
char *str = (char*)dest;//,原字符串指针,这里需要强制类型转换
char *substr = (char*)src;
char *cp = (char*)dest;//用来保存原字符串的起始地址
while (*cp)//保证需要比较的原字符串不为空
{
str = cp;
while ((str != '\0') && (substr != '\0') && (*str == *substr))//判断条件是否成立
{
str++;
substr++;
}
if (*substr == '\0')//判断字串是否比较完
{
return cp;
}
substr = src;//当两个指针不相等时,子串需要回到起始位置重新进行比较
cp++;//原字符串回到起始位置的下一个位置再次进行比较
}
}