C语言字符串相关操作及源码

// 在标准库中,函数不考虑src的'\0'终止字符,始终从src中拷贝count个字符到dst中。
// 建议使用memmove函数代替memcpy
void *memcpy ( void *dst, const void *src, size_t count )
{
    //assert(dst != NULL && src != NULL && count >= 0);
    void * ret = dst;

    /*
     * copy from lower addresses to higher addresses
     */
    while (count--) {
        *(char *)dst = *(char *)src;
        dst = (char *)dst + 1;
        src = (char *)src + 1;
    }

    return(ret);
}
// 首先考虑源地址与目标地址是否存在重叠部分(目标地址是源地址连续内存的一部分),
// 如果有重叠部分从高地址向地址赋值,否则从低地址向高地址赋值。
void *memmove(void *dst, const void *src, size_t count)
{
    //assert(dst != NULL && src != NULL && count >= 0);
    void * ret = dst;
    if (dst <= src || (char *)dst >= ((char *)src + count)) {
        /*
         * Non-Overlapping Buffers
         * copy from lower addresses to higher addresses
         */
        while (count--) {
            *(char *)dst = *(char *)src;
            dst = (char *)dst + 1;
            src = (char *)src + 1;
        }
    }
    else {
        /*
         * Overlapping Buffers
         * copy from higher addresses to lower addresses
         */
        dst = (char *)dst + count - 1;
        src = (char *)src + count - 1;

        while (count--) {
            *(char *)dst = *(char *)src;
            dst = (char *)dst - 1;
            src = (char *)src - 1;
        }
    }
    return(ret);
}

// 把src中所有字符(包括'\0')拷贝到dst中;
 // 如果dst的内存长度小于src,会造成dst越界
char *strcpy(char *dst, const char *src)
{
    //assert(dst != NULL && src != NULL);
    char *ret = dst;
    
    /* Copy src over dst,'*'优先于++,先进行赋值再判断*ret是否有效,无论while()成立与否ret都加1 */
    while (*ret++ = *src++);

    return(dst);
}

// 把src中前count个字符拷贝到dst中;count小于sizeof(src)时拷贝后dst末尾要加'\0'
// 通常count是sizeof(dst)-1的值,防止越界拷贝
char *strncpy(char *dst, const char *src, size_t count)
{
    if (count <= 0)
    {
        return dst;
    }
    char *start = dst;

    while (count && (*start++ = *src++))    /* copy string */
        count--;

    if (count)              // sizeof(dst) 大于 sizeof(src)
        while (--count)
            *start++ = '\0';

    return(dst);
}

// src字符串连接到dst末尾(注意越界)
char *strcat(char *dst, const char *src)
{
    char * cp = dst;

    while (*cp)
        cp++;                   /* find end of dst */

    while (*cp++ = *src++);       /* Copy src to end of dst */

    return(dst);                  /* return dst */
}

char* strncat(char *dst, const char *src, size_t count)
{
    if (count <= 0)
    {
        return dst;
    }
    char *start = dst;

    while (*start)
    {
        start++;
    }

    while (count--)
    {
        if (!(*start++ = *src++))
            return(dst);
    }

    *start = '\0';
    return(dst);
}

// 内存块ptr1前count字节与ptr2前n个字节比较
// 返回值<0: ptr1 < ptr2
//       =0: prt1 == ptr2
//       >0: ptr1 > ptr2
int memcmp(const void *ptr1, const void *ptr2, size_t count)
{
    if (count<=0)
    {
        return 0;
    }
    // 遇到第一个不相等的字符或者count=0时终止
    while (--count && *(char *)ptr1 == *(char *)ptr2)
    { 
        ptr1 = (char *)ptr1 + 1;
        ptr2 = (char *)ptr2 + 1;
    }
    return( *((unsigned char *)ptr1) - *((unsigned char *)ptr2) );
}

int strncmp(const char *ptr1, const char *ptr2, size_t count)
{
    if (count <= 0)
    {
        return 0;
    }

    while (--count && *ptr1 == *ptr2)
    {
        ptr1++;
        ptr2++;
    }
    
    return (*(unsigned char *)ptr1 - *(unsigned char *)ptr2);
}

int strcmp(const char *ptr1, const char *ptr2)
{
    while (*ptr1 == *ptr2)
    {
        ptr1++;
        ptr2++;
    }

    return (*(unsigned char *)ptr1 - *(unsigned char *)ptr2);
}

// 定位value值第一次在buf中的位置,并返回改位置的指针。
// count指定遍历buf多少个字节。
void *memchr(const void *buf, int value, size_t count)
{
    while (count && (*(unsigned char *)buf != (unsigned char)value)) {
        buf = (unsigned char *)buf + 1;
        count--;
    }

    return(count ? (void *)buf : NULL);
}

char *strchr(const char *buf, int character)
{
    while (*buf && *buf != (char)character)
        buf++;

    if (*buf == (char)character)
        return((char *)buf);
    return(NULL);
}

//定位value值最后一次在buf中的位置,并返回改位置的指针
char * strrchr(char *str, int character)
{
    char *start = (char *)str;

    while (*str++);                       /* find end of string */
    /* search towards front */
    while (--str != start && *str != (char)character);

    if (*str == (char)character)                /* char found ? */
        return((char *)str);

    return(NULL);
}

//在buf字符串中的哪个索引位置第一次出现了keys字符串才有的字符
size_t strcspn(const char *buf, const char *keys)
{
    const unsigned char *str = buf;
    const unsigned char *ctrl = keys;

    unsigned char map[16];
    int count;

    /* Clear out bit map */
    for (count = 0; count < 16; count++)
        map[count] = 0;

    /* Set bits in str2 map */
    while (*ctrl)
    {
        map[*ctrl >> 3] |= (1 << (*ctrl & 7));
        ctrl++;
    }

    count = 0;
    map[0] |= 1;    /* null chars not considered */
    while (!(map[*str >> 3] & (1 << (*str & 7))))
    {
        count++;
        str++;
    }
    return(count);
}
//在buf字符串中的哪个索引位置最后一次出现了keys字符串才有的字符
size_t strspn(const char *buf, const char *keys)
{
    const unsigned char *str = buf;
    const unsigned char *ctrl = keys;

    unsigned char map[16]; // VS提供的源码中,map是32个元素
    int count;

    /* Clear out bit map */
    for (count = 0; count < 16; count++)
        map[count] = 0;

    /* Set bits in control map */
    while (*ctrl)
    {
        int retn = *ctrl >> 3;
        int rrt = (*ctrl & 7);
        map[*ctrl >> 3] |= (1 << (*ctrl & 7)); // 用16个char元素记录128个ASCII字符
        ctrl++;
    }

    if (*str)
    {
        count = 0;
        while (map[*str >> 3] & (1 << (*str & 7))) // 按照统一算法找到对应字符下标
        {
            count++;
            str++;
        }
        return(count);
    }
    return(0);
}

// 在buf字符串中的哪个索引位置第一次出现了keys字符串才有的字符,返回那个位置的指针
char* strpbrk(const char *buf, const char *keys)
{
    const unsigned char *str = buf;
    const unsigned char *ctrl = keys;

    unsigned char map[16];
    int count;

    /* Clear out bit map */
    for (count = 0; count < 16; count++)
        map[count] = 0;

    /* Set bits in control map */
    while (*ctrl)
    {
        map[*ctrl >> 3] |= (1 << (*ctrl & 7));
        ctrl++;
    }

    while (*str)
    {
        if (map[*str >> 3] & (1 << (*str & 7)))
            return((char *)str);
        str++;
    }
    return(NULL);
}

// strbuf的某段子字符串与sunstring一致,并返回第一个字符相等位置指针
char *strstr(const char *strbuf, const char *substring)
{
    char *cp = (char *)strbuf;
    char *s1, *s2;

    if (!*substring)
        return((char *)strbuf);

    while (*cp)
    {
        s1 = cp;
        s2 = (char *)substring;

        while (*s1 && *s2 && !(*s1 - *s2))
        {
            s1++;
            s2++;
        }

        if (!*s2)
            return(cp);

        cp++;
    }

    return(NULL);
}


#if 0
// 三种字符串分隔方法,每种方法都会修改原字符串的完整性
// strtok方法遍历strbuf;如果strbuf的字符符合delimiters字符串中某个分割字符,把该字符置换为'\0',返回字符串开始位置的指针。剩下的字符串保留在一个全局变量中
// 该方法不适合多线程操作
char *strtok(char *strbuf, const char *delimiters);
// strtok_s是windows下的方法,作用等同于strtok。但是strtok_s把剩余字符串保存到subbuf中。
char *strtok_s( char *strbuf, const char *strDelimit, char **subbuf);
// strtok_r是linux下的方法
char *strtok_r(char *strbuf, const char *delim, char **subbuf);
#endif
// 返回字符串长度('\0'不会计算在内,区别于sizeof)
size_t strlen(char *str);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值