特性描述及模拟实现strlen、strcpy、strcat、strchr、strstr、strcmp、memcpy、memmove
在学习C语言的过程中,不可避免的会经常接触一些库函数,那么有没有小伙伴想过这些库函数怎么实现的呢?
往往这些库函数都是用最精炼最高效的方式写出的,观摩并模拟出库函数的实现,有利于我们对C语言的深入理解。
今天我将我总结的字符串操作函数及其对应的一些小特性告诉大家,共勉。
特性描述及模拟实现
strlen函数
(测量字符串中到第一个’\0’之前字符的总长度)
特性
//strlen需要目标字符串中有’\0’。
//标准函数库中strlen函数的返回值是size_t类型(也就是无符号整形),也就是unsigned int型。因此在比较两个字符串长度是用到两个strlen相减是不对的。
实现
//非递归
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
int count = 0;
assert(str);
while(*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
int ret = my_strlen("hello bit");
printf("%d\n", ret);
return 0;
}
//递归
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
if(*str)
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
int ret = my_strlen("hello");
printf("%d\n", ret);
return 0;
}
//指针相减
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
const char* p = str;
while(*p)
p++;
return p - str;
}
int main()
{
int ret = my_strlen("hello ");
printf("%d\n", ret);
return 0;
}
strcpy函数
(将第二个参数中字符串内容粘贴到第一个参数字符串中,包括’\0’)
特性
//strcpy不考虑目标空间的大小,即使目标字符串空间不够,也会将原字符串拷贝至目标中。
//strcpy需要原字符串中有’\0’。
//strcpy不要求目标字符串中有’\0’,拷贝时会将原字符串中的’\0’也拷贝至目标字符串中。
//strcpy第一个参数不能是常量字符串等不能进行写入的形式。例:将strcpy(“hello”, “hi”);
实现
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char*src)
{
assert(dest && src);
char* p = dest;
while(*p++ = *src++) ;
return dest;
}
int main()
{
char str[10];
my_strcpy(str, "abcdef");
printf("%s\n", str);
return 0;
}
strcat函数
(将第二个参数中字符串内容追加到第一个参数字符串中,将第一个参数字符串末尾的’\0’抹去,并在追加后给末尾加上’\0’)
特性
//strcat不考虑目标空间的大小,即使空间不够,也会将原字符串追加至目标后面。
//strcat需要目标字符串中有’\0’。
//strcat需要原字符串中有’\0’。
//追加时会将目标字符串中的’\0’覆盖掉,同时会将原字符串中的’\0’追加至目标字符串末尾。
//strcat第一个参数不能是常量字符串等不能进行写入的形式。例:将strcat(“hello “, “world”);
实现
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* str = dest;
while(*str)
str++;
while(*str++ = *src++);
return dest;
}
int main()
{
char str[8] = "hello ";
my_strcat(str, "bit");
printf("%s\n", str);
return 0;
}
strchr函数
(在第一个参数字符串中查找是否出现第二个参数字符)
特性
//strchr会返回目标字符串中第一次出现目标字符的地址
//如果strchr没有没有找到改字符,则会返回NULL
//strchr第一个参数可以是常量字符串。
实现
#include <stdio.h>
#include <assert.h>
char* my_strchr(const char* str, char ch)
{
assert(str);
while(*str != ch && *str)
str++;
if(*str == ch)
return (char*)str;
else
return NULL;
}
int main()
{
char str[] = "my name is LaoLi";
printf("%s\n", my_strchr(str, 'L'));
return 0;
}
strstr函数
(在第一个参数字符串中查找是否出现第二个参数字符串,也就是二字符串是否是一的子字符串)
特性
//strstr会返回目标字符串中第一次出现目标字符串的首字符的地址
//如果strstr没有没有找到改字符串,则会返回NULL
//如果第二个参数传递的是空字符串”\0”,strstr则会返回第一个参数的首地址。返回类型为(char*)
//strstr第一个参数可以是常量字符串。
实现
include <stdio.h>
#include <assert.h>
char* my_strstr(const char* dest, const char* src)
{
assert(dest && src);
char* str = (char *)dest;
char *s1, *s2;
if(!*src)
return (char *)dest;
while(*str)
{
s1 = str;
s2 = (char *)src;
while(*s1 && *s2 && (*s1 == *s2))
s1++,s2++;
if(!*s2)
return str;
str++;
}
}
strcmp函数
(对比一二字符串中每个字符的ASCII值,若一字符串中某字符大于二中对应位置字符,则返回正值,若两者字符都相等,则返回0值,否则,返回负值)
特性
//对比时,是在一二字符串中逐个字符比较,比较它们所对应的ASCII值大小
//在某些编译器下,比较得到的返回值是对应字符相减的大小,而VS编译器下比较得到的返回值是1,0,-1。
实现
#include <stdio.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;
}
memcpy函数
(指定要拷贝字符串中字符的长度,拷贝到第一个参数字符串中,不可以拷贝自身)
特性
//由于是内存拷贝,故memcpy相比strcpy可以复制整形数组,结构体,类等。
//memcpy相对于strcpy不容易出现溢出现象,前者可以决定要拷贝的长度。
//内存拷贝时,第三个参数是你想拷贝的字节数。不要搞错了哦
//memcpy返回值为(void *)
实现
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t n)
{
assert(dest && src);
char* str1 = (char *)dest;
while(n--)
*str1++ = *(char *)src++;
return dest;
}
memmove函数
(拷贝指定字符串的指定长度到目标字符串中,可以拷贝自身)
特性
//memmove解决了memcpy不能自身拷贝自身的重叠覆盖问题
//其余特性几乎和memcpy一致
//memcpy与memmove实际功能对比如下:
memcpy
memmove
实现
#include <stdio.h>
#include <assert.h>
void* my_memmove(void *dest, const void* src, size_t n)
{
assert(dest && src);
char *pdest = (char *)dest;
if (pdest < src)
{
//dest<src 左->右
while (n--)
{
*pdest = *(char *)src;
++pdest;
++(char *)src;
}
}
else
//dest>=src 右->左
while (n--)
*(pdest + n) = *((char *)src + n);
return dest;
}
int main()
{
char str[] = "memmove can be very useful......";
my_memmove(str+20, str+15, 11);
puts (str);
return 0;
}