数据结构10————串-从c语言String库源码来学习

数据结构10————串-从c语言String库源码来学习

一.前言

  • 在学习串这一章的时候老师,讲的挺快的。基本只是讲了串的定义,有哪些基本操作。还有串的两种匹配模式。
  • 在学习串的基本操作时,发现好多操作在c语言的String库里都有提供。所以很好奇,在c语言的String库中,这些基本操作都是如何实现的。所以在网上查了一些资料。在博客的后面就是String库中,串基本操作的实现
  • 不得不说,String库的函数实现真的很精炼,简洁,很有美感。如果让我实现,我也是可以实现的,只不过做不得那么简洁。
  • 最后的链接中,我将自己网上搜集的c语言库函数放在其中。如果小伙伴对其他库函数的实现很感兴趣,可以去下载来看看。

二.串的基本概念

1.串的定义
  • 串是由0个或多个字符组成的有限序列。
2.串的基本运算
  • 串的赋值
  • 计算串的长度
  • 按字典顺序比较两个串的大小
  • 将串2连接到串1后面
  • 查找字符出现在字符串的位置
  • 查找子串出现在字符串出现的位置

三.一点准备工作

1.C语言__cdecl的作用
  • 百度百科解释

__cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。

2.const的含义

const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。

3.size_t

unsigned int 类型,无符号,它的取值没有负数。用来表示 参数/数组元素个数

三.string库中串基本运算的实现

1.strcpy

char *strcpy(char *str1, const char *str2);

把字符串str2(包括’\0’)拷贝到字符串str1当中,并返回str1。

char * __cdecl strcpy(char * dst, const char * src)
{
        char * cp = dst;

        while( *cp++ = *src++ )
                ;               /* 将src字符串复制到dst字符串中,直到'\0'' */

        return( dst );
}
2.strncpy

char *strncpy(char *str1, const char *str2, size_t count);

把字符串str2中最多count个字符拷贝到字符串str1中,并返回str1。如果str2中少于count个字符,那么就用’\0’来填充,直到满足count个字符为止。

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )
{
        char *start = dest;

        while (count && (*dest++ = *source++))    /* 复制字符串 */
                count--;

        if (count)                              /* 如果strce字符个数小于count,用'\0'填充*/
                while (--count)
                        *dest++ = '\0';

        return(start);
}

3.strcat

char *strcat(char *str1, const char *str2);

把str2(包括’\0’)拷贝到str1的尾部(连接),并返回str1。其中终止原str1的’\0’被str2的第一个字符覆盖。

char * __cdecl strcat (
        char * dst,
        const char * src
        )
{
        char * cp = dst;

        while( *cp )
                cp++;                   /*使cp指针指向dst字符串尾部*/

        while( *cp++ = *src++ ) ;       /*将src字符串链接到dst后面 */

        return( dst );                  /* 返回 dst */

}
4.strncat

char *strncat(char *str1, const char *str2, size_t count);

把str2中最多count个字符连接到str1的尾部,并以’\0’终止str1,返回str1。其中终止原str1的’\0’被str2的第一个字符覆盖。

注意,最大拷贝字符数是count+1。

char * __cdecl strncat (
        char * front,
        const char * back,
        size_t count
        )
{
        char *start = front;

        while (*front++) //使front指向str1字符串尾部('\0')
                ;
        front--;//是front指向str1最后一个字符串

        while (count--)//将str2前count个字符复制到str1中
                if (!(*front++ = *back++))//如果str2字符串长度小于count,直接停止函数
                        return(start);

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

5.strcmp

int strcmp(const char *str1, const char *str2);

按字典顺序比较两个字符串,返回整数值的意义如下:

  • 小于0,str1小于str2;
  • 等于0,str1等于str2;
  • 大于0,str1大于str2;
int __cdecl strcmp (
        const char * src,
        const char * dst
        )
{
        int ret = 0 ;
        /*ret等于src所指字符和dst所指字符的差*/
        /*当ret不等于1或者dst指向'\0'时循环停止*/
        while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
                ++src, ++dst;

        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;

        return( ret );
}

6.strncmp

int strncmp(const char *str1, const char *str2, size_t count);

同strcmp,除了最多比较count个字符。根据比较结果返回的整数值如下:

  • 小于0,str1小于str2;
  • 等于0,str1等于str2;
  • 大于0,str1大于str2;
int __cdecl strncmp (
        const char * first,
        const char * last,
        size_t count
        )
{
        if (!count)
                return(0);

        /*当count==0或者first指向尾部或者first所指字符不等于last所指字符*/
        while (--count && *first && *first == *last)
        {
                first++;
                last++;
        }

        return( *(unsigned char *)first - *(unsigned char *)last );
}

7.strchr

char *strchr(const char *str, int ch);

返回指向字符串str中字符ch第一次出现的位置的指针,如果str中不包含ch,则返回NULL。

char * __cdecl strchr (
        const char * string,
        int ch
        )
{
        while (*string && *string != (char)ch)
                string++;

        if (*string == (char)ch)
                return((char *)string);
        return(NULL);
}

8.strrchr

char *strrchr(const char *str, int ch);

返回指向字符串str中字符ch最后一次出现的位置的指针,如果str中不包含ch,则返回NULL。

char * __cdecl strrchr (
        const char * string,
        int ch
        )
{
        char *start = (char *)string;

        while (*string++)                       /* String指向字符串的尾部 */
                ;
                                        
        while (--string != start && *string != (char)ch)
                ;

        if (*string == (char)ch)                /*此时String所指是否寻找的元素 */
                return( (char *)string );

        return(NULL);
}

9.strspn

size_t strspn(const char *str1, const char *str2);

返回字符串str1中由字符串str2中字符构成的第一个子串的长度。


/* Routine prototype */
#if ROUTINE == _STRSPN
size_t __cdecl strspn (
#elif ROUTINE == _STRCSPN
size_t __cdecl strcspn (
#else  /* ROUTINE == _STRCSPN */
char * __cdecl strpbrk (
#endif  /* ROUTINE == _STRCSPN */
        const char * string,
        const char * control
        )
{
        const unsigned char *str = string;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

        /*  map数组清空 */
        for (count=0; count<32; count++)
                map[count] = 0;

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

#if ROUTINE == _STRSPN

        /* 1st char NOT in control map stops search */
        if (*str)
        {
                count=0;
                while (map[*str >> 3] & (1 << (*str & 7)))
                {
                        count++;
                        str++;
                }
                return(count);
        }
        return(0);

#elif ROUTINE == _STRCSPN

        /* 1st char in control map stops search */
        count=0;
        map[0] |= 1;    /* null chars not considered */
        while (!(map[*str >> 3] & (1 << (*str & 7))))
        {
                count++;
                str++;
        }
        return(count);

#else  /* ROUTINE == _STRCSPN */

        /* 1st char in control map stops search */
        while (*str)
        {
                if (map[*str >> 3] & (1 << (*str & 7)))
                        return((char *)str);
                str++;
        }
        return(NULL);

#endif  /* ROUTINE == _STRCSPN */

}

10.strcspn

size_t strcspn(const char *str1, const char *str2);

返回字符串str1中由不在字符串str2中字符构成的第一个子串的长度。

11 strpbrk

char *strpbrk(const char *str1, const char *str2);

返回指向字符串str2中的任意字符第一次出现在字符串str1中的位置的指针;如果str1中没有与str2相同的字符,那么返回NULL。

12 strstr

char *strstr(const char *str1, const char *str2);

返回指向字符串str2第一次出现在字符串str1中的位置的指针;如果str1中不包含str2,则返回NULL。

char * __cdecl strstr (
        const char * str1,
        const char * str2
        )
{
        char *cp = (char *) str1;
        char *s1, *s2;

        if ( !*str2 ) //判断str2是否为空
            return((char *)str1);

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

                while ( *s1 && *s2 && !(*s1-*s2) )//当s1或s2指向尾部或者指向的元素相同
                        s1++, s2++;

                if (!*s2)
                        return(cp);

                cp++;
        }

        return(NULL);

}

13 strlen

size_t strlen(const char *str);

返回字符串str的长度,’\0’不算在内。

size_t __cdecl strlen (
        const char * str
        )
{
        const char *eos = str;

        while( *eos++ ) ;

        return( (int)(eos - str - 1) );
}
14 strtok

char *strtok(char *str1, const char *str2);

在str1中搜索由str2中的分界符界定的单词。

对strtok()的一系列调用将把字符串str1分成许多单词,这些单词以str2中的字符为分界符。第一次调用时str1非空,它搜索str1,找出由非str2中的字符组成的第一个单词,将str1中的下一个字符替换为’\0’,并返回指向单词的指针。随后的每次strtok()调用(参数str1用NULL代替),均从前一次结束的位置之后开始,返回下一个由非str2中的字符组成的单词。当str1中没有这样的单词时返回NULL。每次调用时字符串str2可以不同。

char * __cdecl strtok (
        char * string,
        const char * control
        )
{
        unsigned char *str;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

#ifdef _MT
        _ptiddata ptd = _getptd();
#else  /* _MT */
        static char *nextoken;
#endif  /* _MT */

        /* Clear control map */
        for (count = 0; count < 32; count++)
                map[count] = 0;

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

        /* Initialize str. If string is NULL, set str to the saved
         * pointer (i.e., continue breaking tokens out of the string
         * from the last strtok call) */
        if (string)
                str = string;
        else
#ifdef _MT
                str = ptd->_token;
#else  /* _MT */
                str = nextoken;
#endif  /* _MT */

        /* Find beginning of token (skip over leading delimiters). Note that
         * there is no token iff this loop sets str to point to the terminal
         * null (*str == '\0') */
        while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
                str++;

        string = str;

        /* Find the end of the token. If it is not the end of the string,
         * put a null there. */
        for ( ; *str ; str++ )
                if ( map[*str >> 3] & (1 << (*str & 7)) ) {
                        *str++ = '\0';
                        break;
                }

        /* Update nextoken (or the corresponding field in the per-thread data
         * structure */
#ifdef _MT
        ptd->_token = str;
#else  /* _MT */
        nextoken = str;
#endif  /* _MT */

        /* Determine if a token has been found. */
        if ( string == str )
                return NULL;
        else
                return string;
}

15 memcpy

void *memcpy(void *to, const void *from, size_t count);

把from中的count个字符拷贝到to中。并返回to。

void * __cdecl memcpy (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
        {
        extern void RtlMoveMemory( void *, const void *, size_t count );

        RtlMoveMemory( dst, src, count );
        }
#else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
#endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */

        return(ret);
}

16 memcmp

int memcmp(const void *buf1, const void *buf2, size_t count);

比较buf1和buf2的前count个字符,返回值与strcmp的返回值相同。

int __cdecl memcmp (
        const void * buf1,
        const void * buf2,
        size_t count
        )
{
        if (!count)
                return(0);

        while ( --count && *(char *)buf1 == *(char *)buf2 ) {
                buf1 = (char *)buf1 + 1;
                buf2 = (char *)buf2 + 1;
        }

        return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
}

17 memchr

void *memchr(const void *buffer, int ch, size_t count);

返回指向ch在buffer中第一次出现的位置指针,如果在buffer的前count个字符当中找不到匹配,则返回NULL。

void * __cdecl memchr (
        const void * buf,
        int chr,
        size_t cnt
        )
{
        while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
                buf = (unsigned char *)buf + 1;
                cnt--;
        }

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

18 memset

void *memset(void *buf, int ch, size_t count);

把buf中的前count个字符替换为ch,并返回buf。

void * __cdecl memset (
        void *dst,
        int val,
        size_t count
        )
{
        void *start = dst;

#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
        {
        extern void RtlFillMemory( void *, size_t count, char );

        RtlFillMemory( dst, count, (char)val );
        }
#else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
        while (count--) {
                *(char *)dst = (char)val;
                dst = (char *)dst + 1;
        }
#endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */

        return(start);
}

四.c语言库函数下载链接

test7中

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值