引言:在本文章中,我们将进阶讨论C语言字符串函数的问题,即将之前的内容总结并引入一些新内容。
作者:小 琛
欢迎转载,请标明出处
strlen函数
功能:得到某字符串的长度
我们在MSDN上寻找strlen的原型函数以及头文件,看下图
也就是说,strlen函数的参数必须是 "const char * ",且要包含头文件<string.h>
模拟实现:
#include <stdio.h>
/******************************
函数功能:测量字符串长度函数
入口参数:字符串指针
返回值:测量的数字
*******************************/
unsigned int my_strlen(const char *str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
/******************************
函数功能:测量字符串长度函数(递归写法)
入口参数:字符串指针
返回值:测量得到的数字
*******************************/
unsigned int my_strlen1(const char *str)
{
if (*str == '\0')
{
return 0;
}
return 1+my_strlen1(str + 1);
}
strcpy函数
函数定义:char *strcpy( char *strDestination, const char *strSource );
函数功能:将第二个字符串的内容拷贝到第一个字符串,因此第二个字符串为const char *
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
模拟实现:
/******************************
函数功能:字符串拷贝函数
入口参数:目标字符串和原字符串
返回值:目标地址
*******************************/
char* my_strcpy(char *destination,const char* source)
{
char* ret = destination;
assert(source != NULL);
assert(destination != NULL);
while (*destination++ = *source++)
{
;
}
return ret;
}
strcat函数
函数原型:char *strcat( char *strDestination, const char *strSource );
函数功能:将一个字符串追加到另一个字符串的后面
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
模拟实现:
/******************************
函数功能:字符串追加
入口参数:目标字符串和原字符串
返回值:目标地址
*******************************/
char* my_strcat(char* destination, const char* source)
{
char* ret = destination;
assert(source != NULL);
assert(source != NULL);
while (*destination != \0)
{
destination++;
}
while ((*destination++ = *source++) != '\0')
{
;
}
return ret;
}
strcmp函数
函数原型:int strcmp( const char *string1, const char *string2 );
函数功能:比较两个字符串,直到找到某个不相同的或遇到’\0’。
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
比较使用的是ASCLL码表
模拟实现:
/******************************
函数功能:字符串比较
入口参数:两个不可修改的字符串
返回值:0、1、-1
*******************************/
int my_strcmp(const char* str1, const char* str2)
{
int count = 0;
assert(str1 != NULL);
assert(str2 != NULL);
while ((*str1) && (*str2) && (!(count = *(unsigned int*)str1 - *(unsigned int*)str2)))
{
str1++;
str2++;
}
if (count > 0)
return 1;
else if (count < 0)
return -1;
else
return 0;
}
strncpy、strncat、strncmp的用法
字符串库有之前三个函数加n的用法,其作用类似:从第n个开始进行操作,这几个函数不需要进行模拟,但是要学会使用
strncpy
原型:char *strncpy( char *strDest, const char *strSource, size_t count );
作用:将第二个字符串的n个字符拷贝到第一个参数内
例子:
int main()
{
char *p = "good";
char str[20] = "terrible";
strncpy(str, p, 4);
printf("%s", str);
return 0;
}
结果:
strncat
函数原型:char *strncat( char *strDest, const char *strSource, size_t count );
函数功能:将参数2的n个字符追加到参数1后
例子:
int main()
{
char *p = "good";
char str[20] = "terrible";
strncat(str, p, 2);
printf("%s", str);
return 0;
}
结果:
strncmp
函数原型:int strncmp( const char *string1, const char *string2, size_t count );
函数功能:比较前n个字符,相同返回0,不同返回1或-1
int main()
{
char *p = "good";
char *q = "goxx";
int i = 0;
i=strncmp(p, q, 2);
printf("%d", i);
return 0;
}
strstr函数
函数原型:char *strstr( const char *string, const char *strCharSet );
函数功能:在字符串1中查找另一个字符串2首次出现的位置。如果找到匹配的字符串,返回第一次匹配到的字符串的指针,否则返回NULL。
使用例子:
int main()
{
char str[] = "This is a simple string";
char *pch;
pch = strstr(str, "simple");
puts(pch);
return 0;
}
结果:
模拟实现:
/******************************
函数功能:寻找字符串2在字符串1的地址
入口参数:两个不可修改的字符串
返回值:一个地址
*******************************/
char* my_strstr(const char* str1, const char* str2)
{
assert(str1);
assert(str2);
char* cp= (char*)str1;
char* sub=(char*)str2;
char* s1=NULL;
if (*str2 == '\0')
return NULL;
while (*cp)
{
s1 = cp;
sub = (char*)str2;
while (sub&&s1 && (*sub == *s1))
{
sub++;
s1++;
}
if (*sub == '\0')
return cp;
cp++;
}
}
memcpy函数
引言:在使用strcpy的时候,我们可以注意到,strcpy的定义是通过‘\0’实现的,但假如出现一种情况,要拷贝的字符串内含有‘\0’怎么办?memcpy则可以实现
函数原型:void *memcpy( void *dest, const void *src, size_t count );
函数功能:拷贝参数2的n个内容到参数1
strcpy和memcpy主要有以下3方面的区别。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
使用范例:
int main()
{
char *str = "This is a \0 simple string";
char q[40];
memcpy(q, str, 25);
puts(q);
return 0;
}
结果:
模拟实现:
/******************************
函数功能:拷贝函数
入口参数:一个可修改和一个不可修改的指针
返回值:一个地址
*******************************/
void* my_memcpy(void* dest, const void* source,unsigned int count)
{
void* ret = dest;
assert(dest);
assert(source);
while (count--)
{
*(char*)dest = *(char*)source;
dest=(char*)dest+1;
source = (char*)source + 1;
}
return ret;
}
memmove函数
函数原型:void *memmove( void *dest, const void *src, size_t count );
引言:我们在实现拷贝的时候,会遇到拷贝的空间出现重叠的情况。而空间重叠又有两种情况,如下图
结合memcpy模拟的内容,我们可以得出:第一种情况是无法使用memcpy的,原因是会将仍然有用的部分覆盖掉。
这里就要引入另一个函数,memmove函数,该函数在写法上与memcpy类似,只是它兼容了上述的情况,而如何实现该函数呢?
我们根据上图不难得出:
当dest<src,我们应该使用从前往后拷贝
当dest>src,我们需要使用从后往前拷贝
而无重叠部分,任意方法都可以
(这里的从前往后与从后往前都是针对拷贝内容src的)
因此,根据以上逻辑就可以模拟memmove函数
/******************************
函数功能:兼容覆盖区域的拷贝函数
入口参数:一个可修改、一个不可修改的指针、拷贝长度
返回值:一个地址
*******************************/
void* my_memmove(void* dest, const char* src, unsigned int count)
{
assert(dest);
assert(src);
void* ret = dest;
if (dest < src || (char*)dest >= ((char*)src + count))
{
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + count - 1;
src = (char*)src + count - 1;
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
到此,博文结束。
感谢浏览。