库函数的模拟实现
1 .模拟实现strlen
• 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包 含 ‘\0’ )。
• 参数指向的字符串必须要以 ‘\0’ 结束。
• 注意函数的返回值为 size_t,是⽆符号的(易错 )
• strlen的使⽤需要包含头⽂件
方法1:计数器
define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
size_t my_strlen( const char*str)
{
int count = 0;
assert(str != NULL);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char a[] = "student";
size_t b = my_strlen(a);
printf("%zd\n", b);
return 0;
}
方法2:指针-指针
#include <stdio.h>
#include <assert.h>
size_t my_strlen( const char*str)
{
char* start = str;//记录起始位置
assert(str != NULL);
while (*str != '\0')
{
str++;
}
return str-start;
}
int main()
{
char a[] = "student";
size_t b = my_strlen(a);
printf("%zd\n", b);
return 0;
}
方法3:递归
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
size_t my_strlen( const char*str)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char a[] = "fourth";
size_t b = my_strlen(a);
printf("%zd\n", b);
return 0;
}
总结:
前两个方法用到了创建临时变量的方法,第三个方法没有用到临时变量的创建
2 .模拟实现strcpy
• 源字符串必须以 ‘\0’ 结束。
• 会将源字符串中的 ‘\0’ 拷⻉到⽬标空间。
• ⽬标空间必须⾜够⼤,以确保能存放源字符串。
• ⽬标空间必须可修改。
• 学会模拟实现
#include <string.h>
int main()
{
char arr1[] = "hello world";
char arr2[10] = { 0 };
strcpy(arr2, arr1);
printf("%s", arr2);
return 0;
}
#include <string.h>
int main()
{
char arr1[] = "hello world";
char* p = "xxxxxxxxxxxxxxxxxxxx";//常量字符串-不能修改
strcpy(p, arr1);//err
printf("%s\n", p);
return 0;
}//不能实现,因为目的地空间大小不可修改
源头的字符串必须含有’\0’,没有\0,strcpy不能结束
//为的是实现链式访问
//strcpy返回的函数是目标空间的起始地址
#include <string.h>
char* my_strlen(char* dest, const char* str)
{
assert(dest && str);
char*ret=dest;
while(*dest = *str)//拷贝过去字符后,判断表达式的值,当\0拷贝过去后,判断为假,停止循环
{
;
}
return ret;//返回目标空间的地址
}
int main()
{
char arr1[] = "hello world";
char arr2[40] = { 0 };
my_strcpy(arr2, arr1);
printf("%s", arr2);
return 0;
}
++的优先级高于*,但是这个++是后置++,效果延后,先进行 *dest
3 .模拟实现strcat
• 源字符串必须以 ‘\0’ 结束。
• ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
• ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。
• ⽬标空间必须可修改。
strcat的使用
int main()
{
char arr1[66] = "hhhhh ";
char arr2[] = "hello world";
strcat(arr1, arr2);//字符串追加
printf("%s\n", arr1);
return 0;
}
使用注意点
1.找到目标空间的末尾\0
2.再将源字符串拷贝过来
#include <string.h>
//要返回目标空间的起始地址
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 找目标空间的\0
while (*dest != '\0')
dest++;
// //2. 拷贝
while (*dest++ = *src++)
;
return ret;
}
int main()
{
/*char arr1[20] = "he\0lloxxxxx";//只能读到he
char arr2[] = "world";*/
char arr[20] = "abc";
strcat(arr, arr);//字符串追加
printf("%s\n", arr);
return 0;
}
4 .模拟实现strcmp
• 标准规定:
◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串,则返回0
◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
◦ 那么如何判断两个字符串? ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。
strcmp的使用
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret=strcmp(arr1, arr2);
if (ret > 0)
{
printf(">\n");
}
else
{
printf("<=\n");
}
return 0;
}
strcmp的模拟实现
int my_strcmp(const char*str1,const char*str2)
{
assert(str1 && str2);
while (*str1== *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret=my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
5 .一些注意点
举例
- strncpy 函数的使⽤
int main()
{
char arr1[] = "abcdef";
char arr2[] = "adcttttt";
strncpy(arr2, arr1, 4);
printf("%s\n", arr2);
return 0;
}
• 拷⻉num个字符从源字符串到⽬标空间。
• 如果源字符串的⻓度⼩于num,则拷⻉完源字符串之后,在⽬标的后边追加0,直到num个。
- strncat 函数的使⽤
int main()
{
char arr1[40] = "helloworld";
char arr2[] = "supernova";
strncat(arr1, arr2, 4);
printf("%s\n", arr1);
return 0;
}
• Appends the first num characters of source to destination, plus a terminating null-character. (将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 \0 字 符)。
• If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到 \0 的内容追加到destination指向的字符串末尾)。
strncmp函数的使⽤
⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀ 样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0.
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcg";
int ret = strncmp(arr1, arr2,4);
printf("%d\n", ret);
return 0;
}
6 .模拟实现strtok
int main()
{
char arr1[] = "abcdef@woshishuaige";
char buf[256] = { 0 };
strcpy(buf, arr1);
char* sep = "@.";
char* ret = strtok(buf, sep);
printf("%s\n", ret);
return 0;
}
打印结果:
• sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合
• 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记。
• strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串⼀般都是临时拷⻉的内容并且 可修改。)
• strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。
• strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针。
补充要了解的知识
进一步的改进:
int main()
{
char arr1[] = "abcdef@woshishuaige";
char buf[256] = { 0 };
strcpy(buf, arr1);
char* sep = "@.";
char* ret = NULL;
for(ret = strtok(buf, sep);ret!=NULL;ret=strtok(NULL,sep))
{
printf("%s\n", ret);
}
return 0;
}
为什么函数能够记忆上次的位置?
可能具有static关键字
串中不存在更多的标记,则返回 NULL 指针。
补充要了解的知识
[外链图片转存中…(img-Y17xD7pA-1716019561139)]
进一步的改进:
int main()
{
char arr1[] = "abcdef@woshishuaige";
char buf[256] = { 0 };
strcpy(buf, arr1);
char* sep = "@.";
char* ret = NULL;
for(ret = strtok(buf, sep);ret!=NULL;ret=strtok(NULL,sep))
{
printf("%s\n", ret);
}
return 0;
}
为什么函数能够记忆上次的位置?
可能具有static关键字