简单的字符串函数分类
复制:
strcpy strncpy
串联:
strcat strncat
比较:
strcmp
查找:
strstr
求字符串长度:
strlen
以上字符串函数均来源于库函数<string.h>,使用时需引用该头文件
使用方法及源码分析
注:以下使用的字符指针均不为空指针
Copying:
作用:
将源字符串中第一个'\0'和它之前的所有字符放到目标字符串中,相当于复制粘贴,但会将目标字符串的字符覆盖掉。
从定义看出,strcpy函数调用时需要两个指针类型的参数,
其中一个destination(下文简写为dst),指向目标字符串的首元素地址;
另一个为不可变更的source(下文简写为src),即源字符串的首元素地址;
两个参数均为指针变量,传址以节省内存。
strcpy函数的返回值类型为字符指针变量,指向目标字符串的首元素地址,用output标记。
//我们不希望src的值在使用的过程中被改变,所以定义时使用const
char * my_strcpy(char * dst,const char * src)
{
char* output = *dst; //put记录目标空间的首元素地址
while(*src) //源字符串的单个字符不为‘\0’时循环继续,即源字符串还没结束
{
*dst = *src; //源字符串的单个字符对目标空间的单个空字符一一赋值
src++;
dst++;
}
*dst = *src; //最后要把结束符'\0'复制过去
//while循环精简版:> while(*dst++ = *src++); <---别忘了末尾的‘ ; ’
//精简版括号内的条件执行顺序是:先赋值 ——令*dst = *src;
// 再++ ——让src指针和dst指针指向下一个待赋值的字符的地址
// 最后判断——由于括号内是赋值语句,因此循环结束的条件是看*src的值
// 注意15行的src是未自增前的src
return output;
}
int main()
{
char arr1[20] = {0};
char arr2[20] = "Have a good day";
my_strcpy(arr1,arr2);
printf("%s\n",arr1);
return 0;
}
Ps:源字符串必须以'\0'结束,,,
复制时会将'\0'拷贝到目标空间,,,
必须确保目标空间足够大来存放源字符串,,,
strncpy与strcpy十分相似,不同在于strncpy胖了“n”点,即str(n)cpy
strncpy的定义也不同一点,调用三个参数,前两个参数与strcpy相同,第三个参数表示要从源字符串中复制 num 个字节的内容到目标字符串中。注意num的”单位“为1个字节。
num的类型为sisz_t 即unsigned型
char * my_strncpy (char * dst,const char * src,size_t num)
{
char * output = dst;
while(num)
{
*dst = *src;
dst++;
src++;
num--;
}
//while循环精简版:> while(num && (*dst++ = *src++) )
// num--;
if(num) //判断num的长度是否超过源字符串长度
{
while(num--)
{
*dst = '\0'; //若超过了,则将多余字节的内存全部赋值为'\0'
*dst++;
}
//while循环精简版:> while(num--)
// *dst++ = '\0';
}
return output;
}
int main()
{
char arr1[20] = {0};
char arr2[] = "Have a good day";
my_strncpy(arr1,arr2,5); //num的值自己赋,可以使用sizeof( )进行赋值
printf("%s\n",arr1);
}
Ps:如果源字符串的长度小于num的长度,那么会将多余的内存全部赋值为'\0'
Concatenation:
作用:
将目标字符串和源字符串连接起来,类似“A”+“B” == “AB”
由定义可知使用strcat函数需要传两个字符指针变量作为参数,一个是目标字符串的地址dst,另一个是源字符串的地址src,strcat函数的返回值类型为字符指针类型
char* my_strcat(char * dst,const char* src)
{
char* output = dst;
while (*dst) //*dst != '\0'时循环继续,即找到目标函数的结束符
dst++;
//上述循环等价于:> while(*dst++) ;
// dst--; 用以作为条件去判断的是 *dst ,
// 而实际上dst的值却是dst+1,因此要dst要减一指向的才是'\0'的地址
while(*src) //再在结束符处串联要追加的源字符串
{
*dst = *src;
dst++;
src++;
}
*dst = '\0';
//第二个while循环精简版:> while (*dst++ = *src++) ;
return output;
}
char* my_strncat(char* dst, const char* src, size_t num)
{
char* output = dst;
while (*dst)
dst++; //找到目标字符串中'\0'地址
//上述循环等价于:> while(*dst++) ;
// dst--; 用以作为条件去判断的是 *dst,
// 而实际上dst的值却是dst+1,因此要dst要减一指向的才是'\0'的地址
while (num)
{
if (*src)
{
*dst = *src;
dst++;
src++;
}
else
{
*dst = '\0';
return output; //当num的值大于源字符串长度时,会将源字符串后面 一个 字节的内存赋值为'\0'
}
num--;
}
//while精简版:> while(num--)
// if( ! (*dst++ = *src++) )
// return output;
*dst = '\0'; //当num的值小于源字符串的长度时,为目标字符串赋结束符
return output;
}
Ps:
目标空间必须足够大,,,
源字符串必须以'\0'结尾,,,
Comparison:
作用:
比较两个字符串的首个字符的ASCII码,若相同,则继续往后比较直至一方或双方遇到'\0'
若比到最后仍相等,则输出 0
若前者大于后者的ASCII码,则输出一个大于0的数
若前者小于后者的ASCII码,则输出一个小于0的数
从定义来看,strcmp函数的使用需要传两个参数——两个待比较字符串的首元素地址,因此用char * str1 和char * str2 两个字符型指针变量来指向两个待比较字符串的首元素地址,又因为我们两个待比较的字符串不能随意变更,即常量字符串不能改变,因此对两个变量加上const修饰。由定义可知,strcmp函数的返回值类型是整型。
int my_strcmp(const char * str1 ,const char * str2)
{
int ret = 0; //用来存储 str1 和 str2 比较的字符的ASCII码的差值
while(*str1 && *str2) //未遇到 '\0' 时循环继续,即此前的字符都相同,比较继续
{
ret = *str1 - *str2; //以ret作为返回值,用以区分字符串大小
str1++;
str2++;
}
//while简写: while ( ( ! (ret = *str1 - *str2) ) && *str2 )
// str1++, str2++;
// while() 括号中 ret = *str1 - *str2 在赋值的同时作为条件存在,一举两得
return ret;
}
和strcmp函数相比,strncmp函数调用时需要传入第三个参数size_t 即unsigned类型的num。这个num代表的是 num个字节
Searching:
char *strstr( const char *str1, const char *str2 );
作用:
在源字符串str1中查找是否存在目标字符串str2,若存在,返回str2在str1中第一次出现的地址;若不存在,则返回空指针(NULL)
char* my_strstr(const char* str1, const char* str2) //查找子字符串
{
char* now = (char*)str1; //now用来记录当前这一次查找是从第几个字符开始的
char* s1 = (char*)str1;
char* s2 = (char*)str2;
//不直接使用str1和str2是为了方便记录now的位置
if (*str2 == '\0') //当要查找的字符串是空字符串时,直接返回空指针
return NULL;
while (*now!='\0') //从str1的首字符开始,以逐个字符为头和str2进行对比,
{ //直到遇到str1的结束符'\0'
s1 = now;
s2 = (char*)str2;
while (*s2 != '\0' && *s1 == *s2) //对比
{
s1++;
s2++;
}
if (*s2 == '\0') 当查找完成后,返回str2在str1中首次出现的地址
return (char*)now;
now++;
}
return NULL;
}