**str系列函数的由来**
字符串是一中重要的数据类型,但C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或存储于字符数组中。字符串常量很适用于那些不会对它们进行修改的程序。所有其他字符串都必须存储于字符数组或动态内存的分配中。因此就出现了处理字符串的一系列函数,下面让我们一一来认识这些函数。
1、strlen 求字符串长度
字符串长度就是它所包含的字符个数,例如char *str=”abcdef”;那么它的长度就是6
注:(1)求字符串长度只计算字符个数,不算末尾的\0
(2)strlen的返回值是一个无符号整数类型,而在表达式中使用无符号数可能会导致无法预料的结果,例如:
if(strlen(x)>=strlen(y))
if(strlen(x)-strlen(y)>=0)
这两个语句是不相等的,第一条语句会得到你预想的结果但是第二条语句却不会按照你的想法来,因为它的结果永远为真,因为strlen的结果是无符号数,而无符号数的运算结果永远大于0;
了解清楚注意事项之后我们来自己模拟实现strlen,在此会有三种模拟方法:
方法1:使用计数器
int my_strlen(const char *str)
{
int count = 0;
assert(str != NULL);
while (*str)
{
count++;
*str++;
}
return count;
}
方法2:指针减指针的方式
int strlen(const char *str)
{
const char *start = NULL;
assert(str != NULL);
start = str;
while (*str)
{
*str++;
}
return str-start;
}
方法3:用递归的方式实现
int strlen(const char *str)
{
if (*str != '\0')
{
return 1 + strlen(++str);
}
else
return 0;
}
2、不受限制的复制字符串拷贝函数strcpy
何谓“不受限制”呢?最常用的字符串都是不受限制的,所谓的不受限制就是说它们只是通过寻找字符串结尾的‘\0’来判断它的长度。这些函数一般都指定一块内存用于存放结果字符串。在使用这些函数时,程序员必须保证结果字符串不会溢出这块内存。
strcpy是字符串拷贝函数,它的原型如下:
char *strcpy(char *dst,const char *src);
这个函数的作用是把src的内容赋给dst;使用这个函数有以下几个注意事项:
1、如果参数src和dst在内存中出现重叠现象,其结果是未定义的;
2、由于dst参数将进行修改,所以它必须是一个“字符数组”或“指向动态分配内存的数组的指针”,不能使用字符串常量;
3、目标参数以前的内容将被覆盖并丢失。即使源字符串比目标字符串更短,目标字符串最后剩余的字符也会丢失。
了解了该函数的注意事项之后,我们来模拟实现一下:
char *my_strcpy(char *dst, const char *src)
{
char *ret = dst;
assert(dst);
assert(src);
while (*src != '\0')
{
*dst++ = *src++;
}
return ret;
}
注:使用strcpy函数把一个长字符串复制到一个较
短的数组中,导致溢出。
3、受限制的复制字符串拷贝函数strncpy
何谓“受限制”呢?标准库中还包含了一些函数,它们以一种不同的方式处理字符串。这些函数接受一个显示的长度参数,用于限定进行复制或比较的字符数。这些函数提供了一种方便的机制,可以防止难以预料的长字符串从它们的目标数组溢出。
strncpy的函数原型如下:
char *strncpy(char *dst,const char *src,size_t len)
注:strncpy 调用的结果可能不是一个字符串,因此字符串必须以‘\0’结尾,也就是说对目标字符串结尾用‘\0’进行填充。
了解了注意事项之后,我们就来模拟实现一下strncpy函数:
char *my_strncpy(char *dst, const char *src, int len)
{
assert(dst!=NULL);
assert(src!=NULL);
char *pdst = dst;
while (len--)
{
*dst++ = *src++;
}
*dst= '\0';
return pdst;
}
4、连接字符串函数strcat
strcat 函数的作用是把一个字符串(源字符串)添加到另一个字符串(目标字符串)的后面,它的函数原型如下:
char *strcat(char *dst,const char *src);
注:(1)目标字符串也可以是空字符串;
(2)必须保证目标字符串数组剩余的空间足以保存整个源字符串;
(3)不能自己给自己追加。
了解了注意事项之后,我们来模拟实现以下该函数:
char *my_strcat(char *dst, const char *src)
{
char *pdest = dst;
assert(dst);
assert(src);
while (*dst)
{
dst++;
}
while (*src)
{
*dst++ = *src++;
}
return pdest;
}
5、受限制的连接字符串函数strncat
strncat的作用跟strcat的作一样,都是将源字符串的内容追加到目标字符串后面,但是strncat有限制,该限制就是追加多少个字符由你自己来定,加入源字符串中有6个字符,你可以选择追加10个,当然前提是目标字符串中能容纳得下。
strncat的注意事项跟strcat的注意事项相同,下面我们来模拟实现一下strncat:
char *my_strncat(char *dst, const char *src,int len)
{
char *pdest = dst;
assert(dst);
assert(src);
while (*dst)
{
dst++;
}
while (len&&*src)
{
*dst++ = *src++;
len--;
}
*dst = '\0';
return pdest;
}
6、字符串比较函数strcmp
比较两个字符串是对两个字符串中的字符逐个进行比较,例如将字符串s1=“abcd”和字符串s2=“abcc”进行比较,将s1中的第一个字符‘a’的ASCII值和s2中的第一个字符‘a’的ASCII值进行比较,发现相等,然后再接着比较两个字符串中的第二组字符,直到不相等为止,在该例中发现s1中的‘d’和s2中的‘c’不相等,就停止比较。此时如果‘d’大于‘c’就认为s1>s2; 如果‘d’小于‘c’或者s1是s2的子串就认为s1< s2;如果两个字符串完全相等,则认为s1=s2。
该函数的原型如下:
int strcmp(const chat *s1, const char *s2);
了解了比较的原理之后我们再来看一下注意事项:
注:(1)如果s1>s2,则函数返回任意一个大于零的数,
意一个小于零的数,如果s1=s2,则函数返回一个等于零的数;
(2)由于strcmp并不修改它的任何一个参数,所以不存在溢出字符数组的危险;
(3)strcmp函数的字符串参数也必须以‘\0’结尾,否则的话,它将对参数后面的内容进行比较,这个比较没有意义。
现在我们来模拟实现一下该函数:
int my_strcmp(const char *s1, const char *s2)
{
assert(s1);
assert(s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
*s1++;
*s2++;
}
return *s1 - *s2;
}
7、受限制的字符串比较函数strncmp
该函数的原型是:
int (const char *s1,const char *s2,size_t len);
函数说明:
strcmp也用于比较两个字符串,但是它最多比较len个字节,如果两个字符串在第len个字符前存在不相等的字符,就停止比较,并返回结果。如果两个字符串的前len字符相等,函数就返回零。
该函数的注意事项和strcmp相同,了解了这些内容之后,我们来模拟实现一下该函数:
int my_strncmp(const char *s1, const char *s2, int len)
{
assert(s1);
assert(s2);
while (len-- && *s1 &&(*s1==*s2))
{
s1++;
s2++;
}
return *s1 - *s2;
}
8、查找子字符串函数strstr
该函数的函数原型如下:
char *strstr(const char *s1,const char *s2);
函数说明:
该函数查找字符串s1中首次出现s2的位置,并返回一个指向该位置的指针;如果字符串s2并没有完整的出现在s1的任何地方,函数将返回一个空指针;如果字符串s2为空字符串,函数将返回s1。
注:在模拟该函数时,应当考虑全面,如:
s1=”abbbcde”
s2=”bbc”
这种情况。
了清楚之后我们来模拟实现一下该函数:
char *my_strstr(const char *s1, const char *s2)
{
char *ps1 = (char *)s1;
char *ps2 = (char *)s2;
char *cp = (char *)s1;
assert(s1);
assert(s2);
while (*cp!='\0')
{
ps1=cp;
while ((*ps1 == *ps2) && *ps1 && *ps2)
{
ps1++;
ps2++;
}
if (*ps2 == '\0')
return cp;
ps2 = (char *)s2;
cp++;
}
return NULL;
}
9、模拟实现strrstr函数
strstr函数是找子字符串第一次出现的位置,而strrstr是找最后一次出现的位置,如:
s1=“abbbcdefbbcjik”;
s2=”bbc”;
则函数返回”bbcjik”,该函数有两种模拟实现的方式,一种是借助库函数strstr来实现,一种是不借助strstr实现
第一种实现方式:借助strstr来实现:
char *my_strrstr(const char *s1, const char *s2)
{
const char *ps1 = NULL;
const char *last = NULL;
assert(s1);
assert(s2);
if (!*s2)
return (char *)s1;
while (ps1=strstr(s1,s2))
{
last = ps1;
s1 = ps1 + 1;
}
return (char *)last;
return NULL;
}
第二种:不借助strstr实现:
char *my_strrstr(const char *str, const char *src)
{
assert(str);
assert(src);
int len1 = strlen(str);
int len2 = strlen(src);
char *strend = (char *)str + len1 - 1;
char *start = (char *)src;
char *srcend = (char *)src + len2 - 1;
while (*strend != *srcend)
{
strend--;
}
char *cp = strend;
while (start != srcend)
{
if (*cp== *srcend)
{
cp--;
srcend--;
}
}
return cp;
return NULL;
}
10、strchr函数:在字符串中查找一个特定的字符第一次出现的位置
该函数的函数原型如下:
char *strchr(const char *str,int ch);
注:改函数的第二个参数是一个整型值。但是,它包含了一个字符值。strchr函数在字符串str中查找字符ch第一次出现的位置,找到后函数返回一个指向该位置的指针,如果该字符并不存在与该字符串中,则返回一个NULL指针。
该函数的实现如下:
char *my_strchr(const char *str,int ch)
{
assert(str);
while (*str)
{
if (*str == ch)
{
return (char *)str;
}
str++;
}
return NULL;
}
11、strrchr函数:在字符串中查找一个特定的字符最后一次出现的位置
该函数的原型如下:
char *strrchr( const char *str,int ch);
strrchr的功能和strchr基本一致,只是它返回的是一个指向字符串中该字符最后一次出现的位置。
该函数的实现如下:
char *my_strrchr(const char *str, char c)
{
const char *start = str;
while (*str)
{
str++;
}
str--;
while (str >= start)
{
if (*str == c)
{
return (char *)str;
}
str--;
}
return NULL;
}
还有其他的一些字符串系列函数,由于不常用就不在此一一实现了,只要知道它们的用法即可。