在C语言标准库里面,存在一个对字符串数组进行操作的函数的头文件为string.h。
常用的字符串函数有strlen,strcpy,strcat等等。
了解这些字符串函数是如何实现的可以有助于更好的使用这些字符串函数,并且可以加深对C语言的理解。
strlen是获得一个字符串的有效长度,注意计算大小时不包括'\0'。
下面是C语言官方所给出的声明和解释:
strlen的返回值是size_t,是一个无符号整型。形参用const修饰*str,防止*str被修改。
计数法:
size_t my_strlen_1(const char* arr)
{
assert(arr);//断言,防止空指针
size_t count=0;
while (*arr != '\0')
{
arr++;
count++;
}
return count;
}
递归法:
size_t my_strlen_2(const char* arr)
{
assert(arr);
if(*arr=='\0')
return 0;
return my_strlen2(++arr)+1;
}
两种方法都可以计算出一个字符串的长度
strcpy是将字符串拷贝至目标空间内,原字符串必须包含'\0',且目标空间足够存入该字符串。
同样的给出C语言官方所给出的声明和解释:
注意strcpy有返回值,返回值为目标空间的首元素地址。
char* mystrcpy(char* des, const char* str)
{
assert(des&&str);
char* tmp = des;//先保存一下原地址
while (*str != '\0')
{
*des = *str;
des++;
str++;
}
*des = '\0';//最后将'\0'也拷贝过去
return tmp;
}
strcat是将一个字符串拼接到另一个字符串的后面,要求目标空间足够大。
给出C语言官方所给出的声明和解释:
该函数是将source所指向的字符串拷贝到destination指向的字符串的后面,返回目标空间的首元素地址。
char* mystrcat(char* des, const char* source)
{
assert(des&&source);
char* tmp=des;
while (*des!= '\0')//先找到目标字符串的'\0'
des++;
while (*source!= '\0')//将字符串拷贝值目标函数末尾
{
*des= *source;
des++;
source++;
}
*des= '\0';//将'\0'也给目标字符串
return tmp;
}
strcmp逐位比较两个字符串,如果第一个字符串大于第二个字符串返回大于零的数;如果第一个字符串小于第二个字符串返回小于零的数;如果二者相等则返回0。这个大于小于指的是ASCII码值,也就是逐位比较字符的ASCII码值。
给出C语言官方所给出的声明和解释:
int mystrcmp(const char* str1,const char* str2)
{
assert(str1&&str2);
while (1)
{
if (*str1 == '\0'&& *str2 == '\0')//如果都到结尾,说明两个子串相等
{
return 0;
}
else if (*str1 == *str2)//如果相等继续向后判断
{
str1++;
str2++;
}
else if (*str1 > *str2)
return 1;
else
return -1;
}
}
查找字符串中的子串,返回被查找字符串中子串首元素地址。
给出C语言官方所给出的声明和解释:
从官方的文档中可以看出strstr有两种类型,一种是被const修饰,一种未被const修饰,实现功能一样,只是存在一定的权限问题;在str1里面查找是否存在str2子串,如果没有找到则返回空值。
const char* mystrstr(const char* str1, const char* str2)
{
assert(str1&&str2);
const char*pa = str1;
const char*pb = str2;
if (*str1 == '\0')//规定如果查找空字符,返回原字符串
return str1;
while (*str1 != '\0')
{
while (*pb != '\0'&&*pa != '\0')
{
if (*pa == *pb)//逐个比较
{
pa++;
pb++;
}
else
break;
}
if (*pb == '\0')
return str1;//返回字符串子串首元素地址
if (*pa == '\0')//避免进行不必要的计算
return NULL;
str1++;
pa = str1;
pb = str2;
}
return NULL;
}
除了上面的常用的字符串函数,string.h里面还包含一些对内存操作的函数,也非常的好用例如memcpy、memmove、memset等等
memcpy是将source指向的空间里面的内容按字节拷贝到destination所指向的空间,共拷贝num个字节,并返回目标地址;
给出C语言官方所给出的声明和解释:
这里采用void*指针,说明该指针可以指向任意类型的地址,也就说是说,无论什么类型的元素都可以拷贝,直接访问地址进行拷贝。
void* mymemcpy(void* str1, const void* str2, int size)//size字节数
{
assert(str1&&str2);
for (int i = 0; i < size; i++)
{
*((char*)str1+ i) = *((char*)str2+ i);
}
return str1;
}
这里需要强制类型转换,将任意类型的地址转换成char*,这样每次步进都是一个字节,就可以逐字节拷贝。
memset是对指定内存空间写入num个字节,注意写入的值为int类型,只能写入整型,返回值为void*。
同样给出C语言官方所给出的声明和解释:
这里写入的值虽然是int类型,但是在具体实现的过程中,会存在截断,高24位会截断。
void* mymemset(void* ptr,int val,size_t num)
{
assert(ptr);
unsigned char ch = val;//截断,只保留8位无符号类型
for(size_t i=0;i
memcmp、memmove等具体功能可以查看cplusplus.com - The C++ Resources Network
具体的实现方式和上面类似,不在阐述。