前言
作为C语言的初学者,我们常常在程序中会用到字符串函数,也会在使用的过程中或多或少遇到一些bug,这都是因为我们并不清楚字符串函数具体是怎么实现的。所以,我写这篇博客的原因是为了分享我对常见字符串函数的见解以避免在使用字符串函数的过程中产生一些bug。
一、常见字符串函数有哪些?
有求解字符串长度的strlen()函数,拷贝字符串的strcpy()函数,字符串比较函数strcmp(),追加字符串函数strcat()以及查询是否存在子串的strstr()函数等等。
二、常见字符串函数的使用和实现
1.strlen()函数
作为求解字符串长度的函数,我们常在有关字符串的问题中使用。在这里,我给大家进行详细的阐述。
size_t strlen ( const char * str );//strlen函数的声明
从这个函数声明中我们可以得知,strlen()函数的返回值是无符号整数,因为字符串的长度最少都为0。strlen()函数的参数是字符指针,用来接收字符串的首地址,加const进行限定,说明这个字符串的字符不可以通过指针被修改。
说完了函数的声明,我们来看下strlen()函数的模拟实现。
这里我们采用较为简单的计数器的方式:
int my_strlen(const char * str)
{
int count = 0;
while(*str)//只要*str!='\0'递归就继续,实际上'\0'的ASCII码值是0,所以可以省去!='\0',使程序更为简洁。
{
count++;
str++;
}
return count;
}
2.strcpy()函数
作为字符串拷贝函数,我们常在需要备份字符串的时候使用到,也是一种使用较为频繁的函数。
char* strcpy(char * destination, const char * source );
这是strcpy()函数的声明,他有两个参数,一个是目标字符串首元素的地址,另一个使源字符串首元素的地址,返回值是char*类型,通过查阅相关资料可以得知,返回的是指向目标字符串首元素的指针。
在使用strcpy()时我们要注意,源字符串必须以’\0’结尾,如果你定义的源字符串如下所示
char str1[] = {'a','b','c'};//如果拷贝函数用到该字符串,因为没有'\0'的存在,所以就会一直拷贝下去,知道找到'\0'的存在才停止。
//面对这种情况,我们需要在上述字符数组后补上一个'\0'
//char str1[] = {'a','b','c','\0'} 这才是正确的
其次,我们要知道,拷贝字符串的时候,也将源字符串的’\0’也拷贝了进去。
还有,目标字符串的空间必须足够大且可变。
下面,我们来看一下拷贝函数的模拟实现。
char *my_strcpy(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while((*dest++ = *src++))//只要*src!='\0',拷贝就会一直持续下去
{
;
}
return ret;
}
3.strcmp()函数
字符串比较函数,我们刚开始学习C语言的时候,面对字符串的比较,时常会这么做
char str1 = "abcd";
char str2 = "acde";
if(str1>=str2)
{
//str1>=str2 会进行什么操作
}
实际上这种做法是错的的,我们学过了数组的相关知识,我们应该理解,绝大多数时候,数组名记录的是数组首元素的地址,所以在上述代码中我们比较的只是str1数组首元素的地址和str2数组首元素的地址。(地址也有具体的数值,也可以进行比较)。
那么strcmp()函数究竟是什么样子的呢?我们来看一下他的声明:
int strcmp ( const char * str1, const char * str2 );
通过函数声明,我们可以看到,strcmp()有两个参数,str1,str2,且都用const加以限定,所以传递过来的字符串不可通过指针修改。但只看函数声明我们并不清楚是怎么比较的,而且用语言说明没有代码看起来简洁明了。我们来看一下strcmp()的模拟实现。
int my_strcmp(const char* src,const char* dst)
{
assert(src && dst);//断言,如果src或dst有一个空指针,程序就会报错
while (*src == *dst)//*src和*dst相等,循环就继续下去
{
if (*src == '\0')
return 0;//能进行到这一步,说明满足循环条件,所以*src和*dst都等于'\0','\0'是字符串的结束标志,所以返回0,说明两字符串相等。
src++;
dst++;
}
return *src - *dst;//从循环中跳出,说明*src和*dst只有一个为'\0',又因为字符'\0'的ASCII码值为0,如果*src为'\0'说明字符串1小于字符串2,反之相反。
}
4.strcat()函数
strcat()函数我用的并不是很多,所以对他也没有特别深入的了解。只能简单说一下我对strcat()函数的了解。
char * strcat ( char * destination, const char * source );
通过该函数声明,strcat()有两个字符指针变量,返回的是字符指针类型。
使用该函数我们也该注意几点:
1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
下面我们来看下strcat()函数的模拟实现:
char* my_strcat(char* dest,const char* src)
{
assert(dest && src);
char* ret = dest;
//1.找到目标字符串中的'\0'
while (*dest)
dest++;
//2.把源头的数据拷贝过去,包含\0
while (*dest++ = *src++)
;
return ret;//返回的是目标空间的起始地址
}
总结
字符串函数是我们用的比较多的一类函数,我们不应该仅仅只知道怎么使用,还要明白他们是怎么实现的,最主要的还是要多用,多通过代码调试来明白原理。