C语⾔<string.h>头⽂件所包含的部分函数的解析
1.strlen
strlen函数的作⽤是求字符串的长度,传⼊字符串的⾸元素地址,返回该字符串的长度。
注意这⾥返回值的参数为size_t,即⽆符号整形,所以返回值ret也应该是size_t类型。⽽且由于对⽆符号整形进⾏加减运算会得到⽆符号整型,所以⽆法通过⽐较两个函数返回的strlen值进⾏长短⽐较。
//模拟实现strlen函数
size_t my_strlen(const char* arr)
{
assert(arr);//断⾔,保证arr不为空指针
size_t ret = 0;//使⽤变量进⾏计数
while (*arr++)//当*arr=='\0'跳出循环,否则进⼊循环
ret++;//长度+1
return ret;
}
2.strcpy
strcpy函数的作⽤是将源字符串的内容拷贝到⽬标空间。
注意
1.源字符串必须以\0结尾,否则拷贝会继续向后进⾏,直到遇到\0。
2.⽬标字符串必须要有⾜够的空间
//模拟实现strcpy函数
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);//断⾔
char* ret = dest;//保存⽬标字符串⾸元素地址以便返回
while (*dest++ = *src++)//进⾏拷贝
;
return ret;
}
3.strncpy
strncpy的作⽤是将源字符串中指定数量的字符拷贝到⽬标空间中。
但是也有需要注意的地⽅:
如果源字符串字符不够,会⾃动⽤\0补充。⽐如源字符串为"abc",转移6个字符,则会拷贝a b c \0 \0 \0到⽬标空间。
4.strcat
strcat函数的作⽤是追加⼀个字符串到⽬标字符串的结尾。传⼊⽬标字符串的⾸元素地址,与源字符串的⾸元素地址,返回⽬标字符串的⾸元素地址。
使⽤strcat要注意三点
1.源字符串以必须\0结尾以停⽌追加
2.⽬标字符串必须有⾜够空间,所以⽬标字符串必须指定⼤⼩
3.⽬标可以被修改
//模拟实现strcat函数
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);//断⾔
char* ret = dest;//保存⽬标字符串⾸元素地址以便返回
while (*dest)//从⽬标空间起始地址向后寻\0
dest++;
while (*dest++ = *src++)//进⾏追加
;
return ret;
}
可以看到strcat的模拟实现与strcpy的模拟实现过程⾮常相似,仅仅是增加了寻⽬标字符串结尾位置的步骤。
5.strncat
strncat和strcat的作⽤类似,但是指定了追加字符的数量。
要注意,如果源字符串没有以\0结尾,则会在追加结束后再追加上\0,且最多只追加⼀个\0。
6.strcmp
strcmp的作⽤是进⾏两个字符串的⽐较,这⾥⽐较的不是字符串的长度,⽽是⽐较字符的⼤⼩。
假设传⼊的两个数组为strcmp(arr1,arr2)
这⾥⽐较⼤⼩的规则为,从两个字符串的第⼀个字符开始,若同⼀位字符相同,则⽐较下⼀位,若不同,当arr1内的元素ASCII码值⼤于arr2内的元素,那么返回⼀个⼤于0的数,当arr2内的元素ASCII码值⼤于arr1内的元素,则返回⼀个⼩于0的数。若直到两个字符串结束两者都没有出现不等的情况,则返回0,表⽰两个字符串完全相等。
例如 字符串"abcd"与"abc"⽐较则返回值⼤于0(因为d的ASCII码值⼤于abc后的'\0'的ASCII码值)
"abcd"与"abcc"⽐较返回值⼤于0(因为d的ASCII码值⼤于c的ASCII码值)
⽽"abc"与"abc"⽐较则返回0
//模拟实现strcmp函数
int my_strcmp(const char* arr1, const char* arr2)
{
assert(arr1 && arr2);//断⾔
while (*arr1 == *arr2 && *arr1)//当arr1内元素与arr2内元素相等且不为'\0'进⼊循环
arr1++,arr2++;//指针分别+1,指向下⼀个元素
return *arr1 - *arr2;//返回⽐较值,当两者相等时arr1 arr2都指向'\0' 相减为数字0
}
7.strncmp
将两个字符串的前n个字符以strcmp的规则进⾏⽐较
8.strtok
strtok函数将把第⼀个遇到的分割符改为\0,返回第⼀个分割好的字符串的⾸元素地址,传⼊空指针NULL则会从第⼀个分割符的位置向后查下⼀个分割符,如果没有可检索的字符串,则返回⼀个空指针。
例⼦:被检索的字符串arr1="ab#cd@ef" 以及分割符字符串arr2="#@",要将arr1进⾏分割,则
第⼀次使⽤:strtok(arr1,arr2),返回值为元素a的地址 arr1="ab\0cd@ef"
第⼆次使⽤:strtok(NULL,arr2),返回值为元素c的地址 arr1="ab\0cd\0ef"
第三次使⽤:strtok(NULL,arr2),返回值为元素e的地址 arr1="ab\0cd\0ef"
注意在第三次使⽤时,虽然没有寻到分割符,但是strtok仍对e开头的字符串进⾏了检索,所以并没有返回空指针,⽽是返回了元素e的地址。
9.strstr
strstr函数的作⽤是返回字符串中⾸次出现⼦串的地址,不到则返回NULL,并且当字串为空字符串时,返回字符串的⾸元素地址。
模拟实现的逻辑为,⾸先判断arr2是否为空字符串,再进⾏查。
查过程为:每次进⼊循环先判断arr1是否指向\0,若指向\0则说明arr1遍历结束也没有到字串,退出循环,返回NULL。若没有指向\0则进⼊循环,对以arr1为⾸元素的字串进⾏判断,若没有到,则arr1指向下⼀个元素。
对以arr1为⾸元素的字串进⾏判断过程如下:初始化str1与str2指针,分别赋值为arr1与arr2,以供当元素相等时向后查,当查过程中str1不等str2或者任意⼀⽅指向元素为\0时退出循环,判断str2所指向元素是否为\0。若为\0,则说明到了字串,此时返回arr1。
这⾥设计str1与str2的原因在于在判断时要对每⼀个字符为⾸的⼦字符串进⾏判断,若只使⽤arr1与arr2,当在"abbbcd"中查"bbc"时,在arr1指向第⼀个b时,"bbb"并不能与"bbc"匹配,但在下⼀次判断时arr1直接指向了d,arr2指向了⼦串⾥的c,导致⽆法正常进⾏第⼆次判断,结果出错。
//模拟实现strstr函数
char* my_strstr(const char* arr1,const char* arr2)
{
assert(arr1 && arr2);//断⾔
if (!*arr2)//如果arr2为空字符串,返回arr1的⾸元素地址
return (char*)arr1;
while (*arr1)//arr1不指向\0时进⼊循环
{
char* str1 = (char*)arr1;//定义两个指针进⾏字符串的匹配
char* str2 = (char*)arr2;
while (*str1 && *str1 == *str2)//当两者不为\0且相等时进⼊循环
{
str1++;//指针分别指向下⼀个元素
str2++;
}
if (!*str2)//若结束循环后str2指向\0则说明到字串
return (char*)arr1;
arr1++;//匹配失败时arr1指向下⼀个字符
}
return NULL;//不到则返回NULL
}
memcpy函数的作⽤是将源空间的数据以字节为单位拷贝到⽬标空间。并且返回⽬标空间的地址。
//模拟实现memcpy函数
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert(dest && src);//断⾔
void* ret = dest;//保留⽬标空间地址以便返回
while (count--)//拷贝count个字节的数据
{
*(char*)dest = *(char*)src;//拷贝
dest = (char*)dest + 1;//指针指向下⼀个字节
src = (char*)src + 1;
}
return ret;
}
memmove和memcpy的区别是当内存放⽣局部重叠时,memmove保证结果正确,memcpy不保证拷贝结果正确。memmove会检测拷贝的进⾏⽅向并且以不会出错的⽅向进⾏拷贝。
为什么说memcpy可能发⽣错误呢?⽐如将数组{1,2,3,4,5,6,7,8,9,10}内的1 2 3 4拷贝到 3 4 5 6的位置,按逻辑,结果应该是
1,2,1,2,3,4,7,8,9,10
但是从左向右拷贝
拷贝⼀个整形后 第⼀个整形1拷贝到第三个整形的位置后数组变为{1,2,1,4,5,6,7,8,9,10}
拷贝两个整形后 第⼆个整形2拷贝到第四个整形的位置后数组变为{1,2,1,2,5,6,7,8,9,10}
拷贝三个整形后 第三个整形1拷贝到第五个整形的位置后数组变为{1,2,1,2,1,6,7,8,9,10}
拷贝四个整形后 第三个整形2拷贝到第六个整形的位置后数组变为{1,2,1,2,1,2,7,8,9,10}
这与我们设想的结果不同,因为我们拷贝的数据将原有位置的数据覆盖,导致⽆法正常进⾏拷贝。但是memmove在拷贝前会进⾏⽅向判断,以保证拷贝的结果正确。在上⾯的例⼦中,从右向左拷贝,则
拷贝⼀个整形后 数组变为{1,2,3,4,5,4,7,8,9,10}
拷贝两个整形后 数组变为{1,2,3,4,3,4,7,8,9,10}
拷贝三个整形后 数组变为{1,2,3,2,3,4,7,8,9,10}
拷贝四个整形后 数组变为{1,2,1,2,3,4,7,8,9,10}
也就正常完成了我们的拷贝
//模拟实现memmove函数
void* my_memmove(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
if (dest > src)//判断⽬标空间与源空间的关系
{//从右向左拷贝
dest = (char*)dest + count - 1;
src = (char*)src + count - 1;
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
else
{//从左向右拷贝
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
c++中string的用法}
}
return ret;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论