目录
一、处理字符和字符串的库函数
序号 | 函数原型 | 函数功能 |
1 | size_t strlen(const char* str) | 求字符串长度 |
2 | char* strcpy(char* destination, const char* source) | 字符串拷贝 |
3 | char* strcat(char* destination, const char* source) | 字符串追加 |
4 | int strcmp(const char* str1, const char* str2) | 字符串比较 |
5 | char* strncpy(char* destination, const char* source,size_t num) | n个字符串拷贝 |
6 | char* strncat(char* destination, const char* source,size_t num) | n个字符串追加 |
7 | int strncmp(const char* str1, const char* str2) | 前n个字符串比较 |
8 | char* strstr(const char* str1, const char* str2) | 判断str2是否为str1的字串 |
9 | char* strtok(char* str, const char* sep) | 按照sep对str进行分割 |
10 | char* strerror(int errnum) | 将错误码转换成错误信息 |
11 | void* memcpy(void* destination,const void* source,size_t num) | num个字节内存拷贝 |
12 | void* memmove(void* destination,const void* source,size_t num) | 重复空间内存拷贝 |
13 | int memcmp(const void* ptr1,const void* ptr2,size_t num) | num个字节比较 |
二、模拟实现库函数
1.模拟实现strlen
strlen所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止,然后返回计数器值(长度不包含'\0')。
头文件:string.h
//模拟实现strlen
int my_strlen(const char* str)
{
assert(str);
int count = 0; //计数器
while (*str) //当字符串结尾为'\0'跳出循环
{
str++;
count++;
}
return count;
}
int main()
{
char* arr = "abcdefg";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
2.模拟实现strcpy
把从src地址开始且含有NULL结束符的字符串复制到以dest开始的。
头文件:string.h
//模拟实现strcpy
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* tmp = dest; //保存初始位置
while (*dest++ = *src++) //将src解引用赋值给dest 然后++
{ //直到src为'\0',并且将'\0'赋给dest,跳出循环。
;
}
return tmp;
}
int main()
{
char arr[20] = "xxxxxxxxxxx";
char arr1[] = "hello";
my_strcpy(arr, arr1);
puts(arr);
return 0;
}
3.模拟实现strcat
strncat()主要功能是在字符串的结尾追加字符。
头文件:string.h
//模拟实现strcat
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* tmp = dest; //保存初始位置
while (*dest) //解引用dest,直到dest为'\0',跳出循环
{
dest++;
}
while (*dest++ = *src++) //将src解引用赋值给dest 然后++
{ //直到src为'\0',并且将'\0'赋给dest,跳出循环。
;
}
return tmp;
}
int main()
{
char arr[20] = "hello";
char arr1[] = " world";
my_strcat(arr, arr1);
puts(arr);
return 0;
}
4.模拟实现strcmp
功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
头文件:string.h
//模拟实现strcmp
int my_strcmp(const char* s1, const char* s2)
{
assert(s1 && s2);
while (*s1 == *s2) //当s1解引用和s2解引用相同时进入循环
{
if (*s1 == '\0') //*s1==*s2=='\0'返回0
{
return 0;
}
s1++;
s2++;
}
if (*s1 > *s2) //*s1>*s2返回1
return 1;
else
return -1; //*s1<*s2返回-1
}
int main()
{
char arr1[20] = "xxxxxxx";
char arr2[20] = "xxxxxxx";
int ret = my_strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
5.模拟实现strncpy
把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest。
头文件:string.h
//模拟实现strncpy
char* my_strncpy(char* dest, const char* src, size_t num)
{
char* tmp = dest; //记录初始地址
int i = 0;
int len = strlen(src);
for (i = 0; i < num; i++)
{
if (i <= len) //若num小于源字符长度则进行拷贝
{
*dest++ = *src++;
}
else //num大于源字符长度则赋予'\0'
{
*dest = '\0';
*dest++;
}
}
}
int main()
{
char arr1[20] = "xxxxxxxxxxxxxxx";
char arr2[] = "hello world";
my_strncpy(arr1, arr2, 15);
puts(arr1);
return 0;
}
6.模拟实现strncat
strncat()主要功能是在字符串的结尾追加n个字符。
头文件:string.h
//模拟实现strncat
char* my_strncat(char* dest, const char* src, size_t num)
{
char* tmp = dest; //记录初始地址
int i = 0;
int len = strlen(src);
while (*dest) //将dest指向尾部
{
dest++;
}
for (i = 0; i < num; i++)
{
if (i <= len) //若num小于源字符长度则进行拷贝
{
*dest++ = *src++;
}
else //num大于源字符长度则赋予'\0'
{
*dest = '\0';
*dest++;
}
}
}
int main()
{
char arr1[40] = "hello ";
char arr2[] = "world !";
my_strncat(arr1, arr2, 5);
puts(arr1);
return 0;
}
7.模拟实现strncmp
strncmp函数为字符串比较函数,字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。其函数声明为int strncmp ( const char * str1, const char * str2, size_t n );功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
头文件:string.h
//模拟实现strncmp
int my_strncmp(const char* s1, const char* s2,size_t num)
{
assert(s1 && s2);
int i = 0;
while (num--) //当s1解引用和s2解引用相同时进入循环
{
if (*s1 == *s2) //*s1==*s2
{
s1++;
s2++;
}
else
{
if (*s1 > *s2) //*s1>*s2返回1
return 1;
else
return -1; //*s1<*s2返回-1
}
}
return 0;
}
int main()
{
char arr1[20] = "xxxxxxxx";
char arr2[20] = "xxaxx";
int ret = my_strncmp(arr1, arr2, 2);
printf("%d", ret);
return 0;
}
8.模拟实现strstr
用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
头文件:string.h
//模拟实现strstr
char* my_strstr(const char* str1,const char* str2)
{
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*p)
{
s1 = p;
s2 = str2;
//当*s1==*s2时,对s1++和s2++
while ( *s1!='\0' && *s2 != '\0' && (*s1 == *s2))
{
s1++;
s2++;
}
//当*s2 == '\0' 说明在s1中已经找到s2字串,并将此时s1的地址作为返回值
if (*s2 == '\0')
{
return (char*) p;
}
p++;
}
//没有找到,则返回NULL
return NULL;
}
int main()
{
char* arr1 = "abcde";
char* arr2 = "cd";
char* str = my_strstr(arr1, arr2);
printf("%s", str);
return 0;
}
9.模拟实现memcpy
函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
头文件:string.h
//模拟memcpy
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest; //记录起始位置
assert(dest && src);
while (num--) //循环条件
{
*(char*)dest = *(char*)src; //按照字节指针操作 将src解引用后赋给dest
dest = (char*)dest + 1; //目的地址+1
src = (char*)src + 1; //源地址+1
}
return ret;
}
struct a
{
char name[40];
int age;
} person, person_copy;
int main()
{
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
memcpy(person.name, myname, strlen(myname) + 1);
person.age = 46;
/* using memcpy to copy structure: */
memcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
return 0;
}
10.模拟实现memmove
memmove用于拷贝字节,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
头文件:string.h
//模拟实现memmove
//和memcpy比较可以复制相同空间的字节
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest; //记录起始位置
assert(dest && src);
//当目的地址大于源地址进行复制时会产生循环
//
if ( dest >= src )
{
dest = (char*)dest +num - 1; //记录复制目的地址最后一位的位置
src = (char*)src + num - 1; //记录复制源地址最后一位的位置
while (num--) //循环条件
{
*(char*)dest = *(char*)src; //按照字节指针操作 将src解引用后赋给dest
dest = (char*)dest - 1; //目的地址-1
src = (char*)src - 1; //源地址-1
}
}
else
{
while (num--) //循环条件
{
*(char*)dest = *(char*)src; //按照字节指针操作 将src解引用后赋给dest
dest = (char*)dest + 1; //目的地址+1
src = (char*)src + 1; //源地址+1
}
}
return ret;
}
int main()
{
char str[] = "memmove can be very useful......";
my_memmove(str + 20, str + 15, 11);
//输出memmove can be very very useful.
puts(str);
return 0;
}
11.模拟实现memcmp
memcmp函数的原型为 int memcmp(const void *str1, const void *str2, size_t n);其功能是把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
头文件:string.h
//模拟实现memcmp
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
while (num--) //循环条件
{
//对ptr1和ptr2解引用判断是否相等
if (*(char*)ptr1 == *(char*)ptr2)
{
ptr1 = (char*)ptr1 + 1;
ptr2 = (char*)ptr2 + 1;
}
//ptr1 greatr than ptr1 return<0,else return >0
else
return (*(char*)ptr1 - *(char*)ptr2);
}
return 0;
}
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = my_memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);
else printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
return 0;
}
三、总结
本篇博客使用C语言完成了部分字符串和字符串函数的实现。讲解了具体的用法和实例。制作不易,希望各位看官老爷给个三连支持支持。