strtok,strerror,memcpy,memmove,memcmp,memset详细解析及模拟实现

​​​​​​​

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

🐰strtok

🐰strerror

🐰memcpy

🐰模拟实现memcpy

🐰memmove

🐰模拟实现memmove

🐰memcmp

🐰memset


🐰strtok

strtok用于字符串的拆分,引用头文件为#include<string.h>

strtok的原型:

char * strtok ( char * str, const char * delimiters );

str:字符串的首地址

 delimiters:分隔符

注意:返回类型是字符串的首地址

以下就是把2695855992.@qq.com分割成2695855992 qq com

"@.":分隔符

"@."分隔符
#include<stdio.h>
#include<string.h>
int main()
{
    char arr[]="2695855992.@qq.com";
    char buf[30]={0};
    strcpy(buf,arr);
//    char* str=strtok(buf,"@.");//第一次调用时传字符串的首地址
//    printf("%s\n",str);
//    str=strtok(NULL,"@.");//第二次调用时传空指针
//    printf("%s\n",str);
//    str=strtok(NULL,"@.");//依次类推,只要不是第一次都得穿空指针
//    printf("%s\n",str);
    for(char* str=strtok(buf,"@.");str!=NULL;str=strtok(NULL,"@."))//这里使用循环达到以上一样的效果
    {
        printf("%s\n",str);
    }
    return 0;
}

假如字符串是"aaa-bbb-ccc"

1.第一次调用strtok(),传入的参数str是要被分割的字符串{aaa - bbb -ccc},而成功后返回的是第一个子字符串{aaa};

2.而第二次调用strtok的时候,传入的第一个参数应该为NULL,使得该函数默认使用上一次未分割完的字符串继续分割 ,就从上一次分割的位置{aaa-}作为本次分割的起始位置,直到分割结束。

二.注意事项

这里首先需要强调的是strtok函数在进行字符串分解的时候,其第一个参数,即str是在变化的,就像前面说过的一样,其只是对原字符串(str)进行了调整,也就是改变了原字符串。由上面的例子来看,""2695855992@qq.com"是源字符串,在调用strtok对其分解结束后,字符串变成了"26958559920qq0com",其中的' @ ', ' . '替换成了'\0',也就是替换成了字符串结束标志字符,这样在打印或使用的时候都会使得前面的字符串成为一个看起来独立的字符串,即"2695855992"、"qq"、"com",这些字符串还是在源字符串中,只是后面都有了自己的字符串结束标志'\0'而已。

还有一点,strtok的第一个参数不能是常量字符串的指针,由于上面我们提到,strtok分割函数时,是要对原字符串做出改变的,但传入的是常量字符串,是无法做出改变的,从而导致错误

🐰strerror

strerror用于调用库函数失败时翻译错误信息,引用的头文件#include<string.h>

strerror的原型:


char * strerror ( int errnum );

errnum:调用库函数失败,返回的错误码

注意:返回错误码所对应的错误信息的首地址

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
    FILE* pf=fopen("duck.txt.", "r");
    if(pf==NULL)
    {
        printf("%s\n",strerror(errno));//errno是一个全局变量,类型为整形,erron是一个错误码,系统调用出错的时候,会设置一个错误码。因为C语言没有异常处理机制,所以要依靠错误码进行异常情况的处理。
    }
    return 0;
}

我的电脑中没有duck.txt这个文件,所以它会返回一个错误的信息说的就是不存在这样的文件,这就是strerror对错误码翻译

 其实我们还可以自己定义错误码,去查看错误码在库函数所对应的信息,例如

#include<stdio.h>
#include<string.h>
int main()
{
    printf("%s\n",strerror(0));
    printf("%s\n",strerror(1));
    printf("%s\n",strerror(2));
    printf("%s\n",strerror(3));
    printf("%s\n",strerror(4));
    printf("%s\n",strerror(5));
    printf("%s\n",strerror(6));
    printf("%s\n",strerror(7));
    printf("%s\n",strerror(8));
    return 0;
}

🐰memcpy

memcpy用于内存拷贝(什么类型数据都可以),引用头文件#include<string.h>

memcpy的原型:

void * memcpy ( void * destination, const void * source, size_t num );

 destination:目标空间

source:拷贝空间

num:拷贝字节数

注意:返回目标空间的首地址​​​​​​​

注:void*是通用指针类型,可以接受任意类型的数据,不能进行解引用操作

#include<stdio.h>
#include<string.h>
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,0};
    int brr[20]={0};
    memcpy(brr,arr,20);//在arr中拷贝了20个字节
    for(int i=0;i<5;i++)
    {
        printf("%d ",brr[i]);
    }
    return 0;
}
结果:1 2 3 4 5

🐰模拟实现memcpy

#include<stdio.h>
#include<string.h>
void* my_memcpy(void* dest,void* src,size_t num)//将传入数据类型强制转化为字符类型,然后一个字节一个字节进行拷贝,这样就可以实现任何数据类型的拷贝
{
    void* ret=dest;
    while(num--)
    {
        *(char*)dest=*(char*)src;
        dest=(char*)dest+1;
        src=(char*)src+1;
    }
   return ret;
}
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,0};
    int brr[20]={0};
    my_memcpy(brr,arr,20);
    for(int i=0;i<5;i++)
    {
        printf("%d ",brr[i]);
    }
    return 0;
}

🐰memmove

memove用于内存的拷贝(和memcpy一样实现内存拷贝,但是由于编译器的原因,memcpy不能实现拷贝空间和目标空间在一个空间,而memmove可以实现),引用头文件#include<string.h>

memove的原型:

void * memmove ( void * destination, const void * source, size_t num );

destination:目标空间

source:拷贝空间

num:拷贝字节数

注意:返回目标空间的首地址​​​​​​​

#include<stdio.h>
#include<string.h>
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,0};
    int brr[20]={0};
    memmove(arr+2,arr,20);
    for(int i=0;i<5;i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}

🐰模拟实现memmove

#include<stdio.h>
#include<string.h>
void* my_memmove(void* dest,void* src,size_t num)
{
    void* ret=dest;
    if(dest>src)//如果目标空间的首地址大于拷贝空间的首地址,就得实现从后往前拷贝
    {
        while(num--)
        {
            *((char*)dest+num)=*((char*)src+num);//一个字节一字节拷贝
        }
    }
    else{
        while(num--)//如果目标空间的首地址小于或等于拷贝空间的首地址,就得实现从前往后拷贝
        //一个字节一字节拷贝        
        {
            *(char*)dest=*(char*)src;
            dest=(char*)dest+1;
            src=(char*)src+1;
        }
    }
    return ret;
}
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,0};
    int brr[20]={0};
    my_memmove(arr,arr+2,20);
    for(int i=0;i<5;i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}

🐰memcmp

memcmp用于空间的比较函数(字符类型,整形,浮点型...),引用头文件#include<string.h>

memcmp的原型:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

 ptr1:比较的空间的首地址 

ptr2:比较空间的首地址

num:比较的字节数

注意:返回类型为整形    

ptr1>ptr2 返回大于0的数

ptr1==ptr2返回0

ptr1<ptr2   返回小于0的数

🐰memset

memset用于空间设置函数,引用头文件#include<string.h>

memset的原型:​​​​​​​

void * memset ( void * ptr, int value, size_t num );

ptr:设置的空间

value:设置成的值

num:设置的字节数

注意:返回设置空间的首地址

#include<stdio.h>
#include<string.h>
int main()
{
    int arr[]={1,2,3,4,7};//01 00 00 00 02 00 00 00
    memset(arr,0,5);//将arr的5个字节设置成0
    for(int i=0;i<5;i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}
结果:0 0 3 4 7

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸   

  • 32
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 46
    评论
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值