数据结构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);
}