C语言常用字符串函数及模拟实现

1. 字符串函数总结

📖1.1 strlen

size_t strlen(const char* str);
  • 字符串已'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0'
  • 参数指向的字符串必须要以’\0’结束
  • 函数的返回值为size_t(无符号)
#include<stdio.h>
#include<string.h>

int main()
{
    const char* str1 = "abcd";
    const char* str2 = "aq";

    if(strlen(str1) > strlen(str2))
    {
        printf("str1 bigger than str2\n");
    }
    else
    {
        printf("str2 bigger than str1\n");
    }

    return 0;
}

📖1.2 strcpy

char* strcpy(char* destination, const char* source);
  • 源字符串必须以’\0’结束
  • 会将源字符串的’\0’拷贝到目标空间
  • 目标空间必须足够大,以确保能存放源字符串
  • 目标空间必须可变
#include<stdio.h>
#include<string.h>

int main()
{
    char str1[10] = "abcdef";
    char str2[5] = "aaaa";

    strcpy(str1, str2);

    printf("%s\n", str1);

    return 0;
}

📖1.3 strcat

char* strcat(char* destination, const char* source);
  • 源字符串必须以’\0’结束
  • 目标空间必须足够的大,能容纳下源字符串的内容
  • 目标空间必须可修改

📖1.4 strcmp

int strcmp(const char* str1, const char* str2);
  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
#include<stdio.h>
#include<string.h>

int main()
{
    char str1[10] = "abcde";
    char str2[5] = "aaaa";

    int ret = strcmp(str1, str2);
    if(ret > 0)
    {
        printf("str1 > str2\n");
    }
    else if(ret == 0)
    {
        printf("str1 = str2\n");
    }
    else
    {
        printf("str1 < str2\n");
    }

    return 0;
}

📖1.5 strncpy

char* strncpy(char* destination, const char* source, size_t num);
  • 拷贝num个字符从源字符串到目标空间
  • 如果源字符串的长度小于num,则拷贝完源字符串后,在目标的后面追加'\0',直到num
#include<stdio.h>
#include<string.h>

int main()
{
    char str1[10] = "abcde";
    char str2[5] = "aaaa";

    strncpy(str1, str2, 3);
    printf("%s\n", str1);

    return 0;
}

📖1.6 strncat

char* strncat(char* destination, const char* source, size_t num);
#include<stdio.h>
#include<string.h>

int main()
{
    char str1[20] = "abcde";
    char str2[5] = "aaaa";

    strncat(str1, str2, 3);
    printf("%s\n", str1);

    return 0;
}

📖1.7 strncmp

#include<stdio.h>
#include<string.h>

int main()
{
    char str1[20] = "abcde";
    char str2[5] = "abcdf";

    int ret = strncmp(str1, str2, 4);

    printf("%d\n", ret);

    return 0;
}

📖1.8 strstr

char* strstr(const char* str2, const char* str1);
#include<stdio.h>
#include<string.h>

int main()
{
    char str1[20] = "abcd";
    char str2[10] = "abcdf";

    char* p = strstr(str2, str1);

    printf("%s\n", p);
    return 0;
}

📖1.9 strtok

char* strtok(char* str, const char* sep);
  • sep是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或多个分隔符分隔的标记
  • strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针
  • strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置.
  • strtok函数的第一个参数为空NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
  • 如果字符串中不存在更多的标记,则返回空指针.
#include<stdio.h>
#include<string.h>

int main()
{
    char* pstr = "2893992451@qq.com";
    char arr[30];
    const char* sep = "@.";

    strcpy(arr, pstr);
    char* str = NULL;

    for(str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
    {
        printf("%s\n", str);
    }


    return 0;
}

📖1.10 strerror

char* strerror(int errnum);

功能:该函数返回错误码所对应的错误信息.

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件

int main ()
{
    FILE * pFile;
    pFile = fopen ("unexist.ent","r");
    
    if (pFile == NULL)
      printf ("Error opening file unexist.ent: %s\n",strerror(errno));
    //errno: Last error number
  
    return 0;
}

📖1.11 memcpy

void* memcpy(void* destination, const void* source, size_t num)
  • 函数memcpysource的位置开始向后复制num个字节的数据到destination的位置
  • 这个函数在遇到'\0'的时候并不会停下来
  • 如果destinationsource有任何的重叠,复制的结果都是未定义的
struct person
{
    char name[20];
    int age;
};

int main()
{
    //拷贝字符串
    struct person LiHua;
    char name[] = "LiHua";
    memcpy(LiHua.name, name, strlen(name) + 1);

    LiHua.age = 10;

    printf("%s %d\n", LiHua.name, LiHua.age);

    //拷贝结构体
    struct person copyPerson;
    memcpy(&copyPerson, &LiHua, sizeof(LiHua));
    printf("%s %d\n", copyPerson.name, copyPerson.age);

    return 0;
}

📖1.12 memmove

void* memmove(void* destination, const char* source, size_t num);
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的

📖1.13 memcmp

int memcmp(const char* ptr1, const char* ptr2, size_t num);
  • 比较从ptr1ptr2指针开始的num个字节

image-20221015231730954

int main()
{
    char s1[] = "abcdefg";
    char s2[] = "adcefg";

    int ret = memcmp(s1, s2, 4);

    if(ret > 0)
        printf("s1 > s2\n");
    else if(ret < 0)
        printf("s1 < s2\n");
    else
        printf("s1 = s2\n");

    return 0;
}

2. 字符分类函数总结

函数如果它的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符'\t',或者垂直制表符'\v'
isdigit十进制数字0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~Z
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~zA~Z
isalnum所有字母或者数字
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

字符转换:

int tolower(int c);
int toupper(int c);

3. 字符串函数模拟实现

📖3.1 模拟实现strlen

第一种方式:

//计数器方式
int mystrlen(const char* str)
{
    int count = 0;
    while(*str)
    {
        count++;
        str++;
    }

    return count;
}

第二种方式:

//使用递归
int mystrlen(const char* str)
{
    if(*str == '\0')
        return 0;
    else
        return mystrlen(str + 1) + 1;
}

第三种方式:

int mystrlen(const char* str)
{
    const char* pstr = str;

    while(*pstr != '\0')
        pstr++;
    
    return pstr - str;
}

📖3.2 模拟实现strcpy

char* my_strcpy(char* dest, const char* src)
{
    char* ret = dest;

    assert(dest != NULL);
    assert(src != NULL);

    while(*dest++ = *src++)
        ;
    
    return ret;
}

📖3.3 模拟实现strcat

char* my_strcat(char* dest, const char* src)
{
    char* ret = dest;

    assert(dest != NULL);
    assert(src != NULL);

    while(*dest)
        dest++;
    
    while((*dest++ = *src++))
        ;
    
    return ret;
}

📖3.4 模拟实现strstr

char* my_strstr(const char* str1, const char* str2)
{
    char* cp = (char*)str1;

    if(!*str2)
        return (char*)str1;

    char* s1, *s2;
    while(*cp)
    {
        s1 = cp;
        s2 = (char*)str2;

        while(*s1 && *s2 && !(*s1 - *s2))
            s1++, s2++;
        
        if(!*s2)
            return cp;
        
        cp++;
    }

    return NULL;
}

📖3.5 模拟实现strcmp

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    int ret = 0;
    while(!(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1)
        ++str1, ++str2;
    
    if(ret > 0)
        ret = 1;
    else if(ret < 0)
        ret = -1;

    return ret;
}

📖3.6 模拟实现memcpy

void* my_memcpy(void* dst, const void* src, size_t num)
{
    assert(dst != NULL);
    assert(src != NULL);

    void* ret = dst;

    while(num--)
    {
        *(char*)dst = *(char*)src;
        dst = (char*)dst + 1;
        src = (char*)src + 1;
    }

    return ret;
}

📖3.7 模拟实现memmove

void* my_memmove(void* dst, const void* src, size_t num)
{
    assert(dst != NULL);
    assert(src != NULL);

    void* ret = dst;

    if(dst <= src || (char*)dst >= (char*)src + num)
    {
        while(num--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst + 1;
            src = (char*)src + 1;
        }
    }
    else
    {
        dst = (char*)dst + num - 1;
        src = (char*)src + num - 1;

        while(num--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst - 1;
            src = (char*)src - 1;
        }
    }

    return ret;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默.@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值