string头文件中常用函数

1.1strlen求字符串长度

strlen是一个库函数所包含的头文件为#include<string.h>,这里我们可以在C plusplus上找到strlen所包含的头文件以及strlen传入后函数所生成的一个参数
在这里插入图片描述
这个函数返回的类型为siz_t的值为无符号整形为正数(>=0)的数,参数为const char* str,你需要传入一个字符类型相关的数据来求出从起始地址->'\0’所有符号的长度
在这里插入图片描述
结果为
在这里插入图片描述
因为传入的是arr,arr为你的首元素地址作为参数传入到strlen函数中
因为字符串中大部分都有所对应的ASCII
ASCII值地址

1.2模拟实现strlen函数

如何模拟strlen求出字符串的长度,首先我们肯定需要知道strlen这个函数所需要的函数参数以及返回类型
在这里插入图片描述
如图所示,strlen的返回类型为size_t,它的参数是const char* str
我们先写代码来理解他的含义

#include<stdio.h>
#include<assert.h>
size_t My_strlen(const char* str)
//const为char*类型的指针指向的变量无法进行修改
{
    assert(str);     //==assert(str!=NULL)不为空指针
    size_t count = 0;//数量从0开始返回count类型
    while (*str++)//这里进去之后再去指向数组中第二个地址
    {
       count++ ;//数量++
    }
    return count;
}
int main()
{
    char arr[] = {"abcdef"};
    size_t rec = My_strlen(arr);
    printf("%zu",rec);
    return 0;
}

2.1 strcpy函数

strcpy也是一个经常使用到的函数,cpy顾名思义就是拷贝的意思,他就是将一个字符串拷贝到数组中(你的数组需要将字符串容纳进去)
在这里插入图片描述

它的返回类型也是char* 而参数第一个destination为目的地,将你想要考入的数据放到参数1中,source为源头,至于为什么第二个参数有const第一个没有,因为第二个是你需要将源头的内容拷贝到目的地,源头肯定不可以修改,而目的地这时候已经被修改,参数1不需要加const
在这里插入图片描述
在这里插入图片描述
可以看到已经将str中的字符串拷贝到arr中(如果arr中有字符的情况下,目的地的字符会被源头的字符覆盖掉,源头字符直到\0停止)

2.2 模拟实现strcpy

#include<stdio.h>
#include<assert.h>
char* My_strcpy(char* dest,const char*s)
{
    char *ret = dest;
    assert(s);
    while (*s)
    {
        *dest++= *s++;//将s的字符放到dest中++寻找下个字符
    }
    *dest = *s;//因为while循环\0为0终止循环,最后在拷贝\0,
    return ret;//返回首元素的地址
}
int main()
{
    char arr[30] = {"abcedeadwadwadada"};
    char str[15] = {"Hello, World"};
    My_strcpy(arr,str);
    printf("%s", arr);
    return 0;
}

3.1strcat函数

在这里插入图片描述
在这里插入图片描述
strcat函数介绍为:将源字符串的副本追加到目标字符串,destination中的结束null字符被source的第一个字符覆盖,并且在destination中由两者串联形成的新字符串的末尾包含一个空字符。
目的地和源头不得重叠。
这里的意思就是目的地中的第一个\0会被第一个字符覆盖然后继续覆盖,当源头的字符串覆盖完成生成一个新的\0

在这里插入图片描述
在这里插入图片描述
这里我们可以看到arr1中追加了arr2中的字符。

3.2模拟实现strcat

这里的传入参数的值和上面的步骤相同可以看一下上面
代码实现

#include<stdio.h>
#include<assert.h>
char* My_strcat(char* dest,const char* src)
{
    char *ret = dest;
    assert(dest && src);
    // char* rec = *dest;
    while (*dest!='\0')
    //首先因为我们知道了目的地的值第一个\0开始开始覆盖的,所以我们需要得到找到\0
    {
        dest++;//这里找到第一个\0
    }
    while(*dest++ = *src++)//这里我们开始从第一个\0开始被src覆盖
    {
        ; // *dest++=*src++//也可以这么写
    }
    return ret;
}
int main()
{
    char arr1[30] = {"abcde"};
    char arr2[10] = {"abcd"};
    My_strcat(arr1,arr2);
    printf("%s", arr1);
    return 0;
}

在这里插入图片描述

4.1 strcmp函数

在这里插入图片描述
strcmp函数返回的是int类型,参数为两个,这里可以看到const这个函数开始
比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对,直到字符不同或达到终止空字符为止
在这里插入图片描述

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[] = {"abcd"};
    char arr2[] = {"abcd"};
    int ret = strcmp(arr1, arr2);
//  它的返回值为int因为既返回整数又返回有符号整数又返回0
    if(ret>0)
        printf("大于0");//比较两个数ASCII码值大小不是长度大小
    else if(ret<0)
        printf("小于0");
    else
        printf("==");
    return 0;
}

4.2模拟实现strcmp函数

因为我们知道了strcmp是作为比较的函数而返回的结果是有符号的整数,参数为p1和p2这里我们可以实现一下

int My_strcmp(const char* str1,const char* str2)
{
    while(*str1==*str2)
    {
        if(*str1=='\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1 - *str2;//如果大于str2返回正数,如果小于返回负数
}
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcde";
   int ret =  My_strcmp(arr1, arr2);//ret来接收函数返回值
   if(ret>0)
       printf("大于目标字符串");
    else if(ret<0)
        printf("小于目标字符串");
    else
        printf("两个字符串相等");
}

5.1strstr函数

在这里插入图片描述
返回指向str1中str2第一次出现的指针,如果str2不是str1的一部分,则返回空指针
这里的意思是str2作为str1中作为子集,从str1中寻找str2所有的字符串,然后以一个char*变量来接收如果可以找到就返回结果,找不到返回NULL

#include<string.h>
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "ef";
    char *ret = strstr(arr1, arr2);
    if(ret==NULL)
        printf("找不到");
    else
        printf("找到了%s", ret);
}

5.2模拟实现strstr

#include<stdio.h>
#include<assert.h>
const char* My_strstr(const char* str1,const char* str2)
{
    assert(str1 && str2);
    const char *a = str1;
    const char *b = str2;
    const char *num = str1;//记录可能开始匹配的位置并返回num值
    while(*num)
    {
        a = num;//当num++后,说明第一次循环的初始位置没有找到\0,需要从第二个字符开始寻找
        b = str2;//str1中的最开始的位置到\0没有找到b需要赋原值
        while (*a && *b && *a == *b) // 如果a=b,说明字符相同,开始循环进来
        //a和b不能为\0,是\0没有比较的字符
        {
            a++;
            b++;
        }
        num++;
         if(*b=='\0')//如果*b已经找到\0了说明在str1中找到了str2
        {
            return num;//num记录了我们最开始的位置,在num的基础上被a赋值++,num没有变化
        }
    }
    return NULL;
}
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "ef";
    const char* ret = My_strstr(arr1, arr2);
    if(ret ==NULL)
        printf("Not found");
    else
        printf("Yeah the character has been found: %s", arr1);
    return 0;
}```
# 6.1 strncpy函数
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/3e2ec05926614527a200c4505b746eff.png)
这个函数和strcpy很相似,官网的功能为strncpy参数第一个为destination,参数二为source,参数三为你要将前n个拷贝到目的地
函数实现

```c
#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[] = "abcd";
    char arr2[] = "dcba";
    strncpy(arr1,arr2,2);
    //如果该目标的符号内容不够,需要追加的补\0,strncpy和strcpy只是覆盖不是拼接,将原目的地的字符串内容改变
    printf("%s", arr1);
    return 0;
}

6.2 模拟实现strncpy

char* My_strncpy(char* dest,const char*s,size_t n)
{
    char* ret = dest;
    int num=n;//将一共需要覆盖多少次赋值给num
    while (*s &&num--)num--当num或者s中其中一个条件不满足跳出循环
    {
        *ret++ = *s++;
    }
    for (int i=num; i <=n; i++)//如果num目前已经==n,那么就不满足条件
    {
        *ret++ = 0;
    }
    return dest;
}
int main()
{
    char arr1[] = "abcde";
    char arr2[] = "fghj";
    My_strncpy(arr1, arr2, 6);
    printf("%s", arr1);
    return 0;
}

7.1strncat函数实现

在这里插入图片描述
strncat的意思是将source中的num个字符拼接到destination中

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[20] = "abcdef";
    char arr2[20] = "poiuy";
    strncat(arr1, arr2,5);//第三个参数指定追加n个字符到目的地,
    //如果传入的追加个数,少于scource的个数,条件不满足的情况下只会追加一个\0
    printf("%s", arr1);
    return 0;
}

7.2模拟实现strncat

#include<stdio.h>
#include<assert.h>
char* My_strncat(char* dest,const char* src,size_t n)
{
    char *ret = dest;
    assert(dest && src);
    while(*dest!='\0')
    {
        dest++;
    }
    while(n--)
    {
        *dest++ = *src++;
    }
    *dest = '\0';
    return ret;
}
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "cde";
    My_strncat(arr1, arr2, 5);
    //arr1为目的地,arr2为源头,4为将源头的4个字符拼接到arr1
    printf("%s", arr1);
    return 0;
}

8.1memcpy函数

在这里插入图片描述
将num字节的值从源指向的位置直接复制到目标指向的内存块。
源指针和目标指针所指向的对象的底层类型与此函数无关;结果是数据的二进制副本。
该函数不检查源中是否有任何终止null字符——它总是精确地复制num个字节。
为了避免溢出,目标参数和源参数所指向的数组的大小应该至少为num字节,并且不应该重叠(对于重叠的内存块,memmove是一种更安全的方法)。
这个函数的功能和strncpy类似,但是传入的值是以字节为单位,在内存块中以字节的形式复制给destination,我们都知道char*中一个字符单位为1

#include<string.h>
int main()
{
    int arr1[] = {1, 2, 1,3,3,1,2};
    int arr2[] = {1, 2, 1, 2, 0};
    int sz = sizeof(arr1) / sizeof(arr1[0]);
    memcpy(arr1, arr2, 3 * sizeof(int));
    for (int i = 0; i < sz;i++)
    {
        printf("%d ", arr1[i]);
    }
        return 0;
}

8.2模拟实现memcpy

#include <stdio.h>
#include <string.h>
#include<assert.h>
void* My_memcpy(void* dest,const void* src,size_t n)
//我们传入的是3*sizeof(int)类型,sizeof(int)类型占4个字节,*3为12;
//我们传进来的参数为12
{
    void *p = dest;
    assert(dest && src);
    if(src==(void*)0)
    {
        return 0;
    }
    while(n--)//需要循环12次
    {
        *(char *)dest++ = *(char *)src++;
        //我们将源头的数据以内存字节的形式置入给dest然后++找下一个字节的空间
        //memcpy内部实现只是单纯的进行地址内容的赋值操作,并没有对重叠区域进行处理。这就会导致到dst和src的地址存在重叠的时候拷贝出现异常。
    }
    return p;
}
int main ()
{
    char a[] = {"abcdefg"};
    char b[] = {"poiuytt"};
    My_memcpy(a, b,2*sizeof(char));
    char ret = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < ret;i++)
    {
        printf("%c ", a[i]);
    }
    return 0;
}

9.memmove函数

在这里插入图片描述
将num字节的值从源指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠。
源指针和目标指针所指向的对象的底层类型与此函数无关;结果是数据的二进制副本
该函数不检查源中是否有任何终止null字符——它总是精确地复制num个字节。
为了避免溢出,目的参数和源参数所指向的数组的大小至少为num字节。
memcpy和memmove的参数和使用方式是一样的
而memcpy不考虑重叠的情况,而memmove考虑重叠的情况

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

9.1模拟实现memmove

在这里插入图片描述

#include<stdio.h>
void* My_memmove(void* dest,void* src,size_t n)
{
    void *ret = dest;
    if (dest < src)
    {
        //从前-后
    while(n--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;//强制类型转换为char*类型,因为char为一个字节+1跳到下一个字节
        src = (char*)src + 1;
    }
    }
    else
    {
      //从后-前
     while(n--)
    {
        *((char*)dest + n) = *((char*)src + n);
    }
    }
    return ret;
}
int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
     int sz = sizeof(arr) / sizeof(arr[0]);
     My_memmove(arr+2, arr, 5 * sizeof(int));
     //arr为目标地址,arr+2由第第三个地址拷贝五个元素到arr中
    for (int i = 0; i < sz;i++)
    {
        printf("%d ", *(arr + i));
    }
        return 0;
}

10.memset函数

在这里插入图片描述
将ptr指向的内存块的前num个字节设置为指定的值(解释为unsigned char)。
第一个参数为要设置内存的指针 value为设置的值,num为设置的字节个数
memset是以字节单位来设置的,而不是以元素个数为单位设置
通常情况下这个函数是用来将所有字节数设置为0
如果设置为其他数一定要记得他是将内存中每个字节的数进行修改,而不是修改元素

#include<stdio.h>
#include<string.h>
int main()
{
    int arr[10] = {0};
    for (int i = 0; i < 10;i++)
    {
        arr[i] = i+1;
    }
    //1,2,3,4,5,6,7,8,9,10
    memset(arr, 0, 10 * sizeof(int));
   
    for (int i = 0; i < 10;i++)
    {
        printf("%d ",*(arr+i));
    }
        return 0;
        //如果想要修改char类型字符个数可以直接修改,因为char本身占用一个字节,int类型占用4个
}

11.memcmp函数

在这里插入图片描述
ptr1和ptr2进行比较指向要比较的内存空间,num为比较的字节个数,在num中比较如果ptr1>ptr2返回1,小于返回负数 相同为0

#include<stdio.h>
#include<string.h>
int main()
{
    int arr1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    // 比较字节的个数
    int arr2[] = {1, 2, 3,3};
    int ret = memcmp(arr1, arr2, 13);
    printf("%d",ret);
    //在内存中有大端字节序与小端字节序,高位字节数据存放在内存高地址处,低位数据存放在内存低地址处
    //高位字节数据存放在内存低地址处,低位字节数据存放在内存高地址处
    return 0;
}
//在大小关系成立后,就不会再次进行比较

12.strtok函数

strtok函数回找到str中的下一个标记,并以\0结尾,返回一个指向这个标记的指针。
strtok函数会改变被操作的字符串,所以在strtok函数切分字符串一般都是临时拷贝的内容可以修改。
strtok第一个参数如果不为NULL,函数找到str中第一个标记,strtok函数将保存他在字符串中的位置。
strtok函数第一个参数如果为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多标记,则返回NULL指针
返回类型为char*
在这里插入图片描述

#include<stdio.h>
#include<string.h>
int main()
{
    // char arr[] = "abcd@yeah.com.c";
    char arr[] = "123@323.909.404";
    char *p = "@.";//分隔符尽量是符号,但是数字也可以作为分割符
    char buf[20] = {0};
    strcpy(buf, arr);
    // char* a = strtok(buf, p);
    // printf("%s\n", a);//返回第一个标记前的内容
    // a = strtok(NULL, p);
    // printf("%s\n", a);//返回第二个标记前内容,为NULL
    // a = strtok(NULL, p);//🈶第二个标记开始从返回\0的内容找
    // printf("%s", a);
    char *ret = NULL;
    for (ret = strtok(buf, p); ret != NULL;ret = strtok(NULL,p))
    //第一次传入为非NULL指针,当第一次调用后为NULL
    {
        printf("%s\n", ret);
    }
        return 0;
}

13.strerror函数

可以将errnum错误码,返回一个错误信息
获得一个指针指向一个错误信息
c语言的库函数在运行的时候,如果发生错误,就会将错误码放到一个变量中,这个变量是error。

在这里插入图片描述

#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(3));
    printf("%s\n", strerror(4));
    printf("%s\n", strerror(5));
    return 0;
}

14.perror函数

perror返回类型为void,参数为字符串
perror直接打印出错误的信息
perror可以理解为printf+strerror结合形式
在这里插入图片描述

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
    FILE* pf= fopen("Xcode", "r");//如果没写路径默认打开的是你当前路径下的文件夹
    if(pf==NULL)
    {
        perror("fopen");//在打印错误信息前,先打印自定义的信息
        return 1;
    }
    // else printf("打开成功\n");
    //读取文件
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

15.fopen函数

在这里插入图片描述
fopen的函数参数第一个参数为文件名,第二个为打开方式
如果打开成功可以返回一个有效的指针FILE*,返回失败返回NULL

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
    FILE* pf= fopen("Xcode", "r");//如果没写路径默认打开的是你当前路径下的文件夹
    if(pf==NULL)
    {
        printf("%s",strerror(errno));//strerror包含string库函数,errno是errno库函数
        return 1;
    }
    // else printf("打开成功\n");
    //读取文件
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}
  • 29
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值