目录
库函数strtok(包含在头文件string.h中)
一系列字符分类函数(包含在头文件ctype.h中)
库函数strtok(包含在头文件string.h中)
一、库函数strtok的定义:
1.参数str是指向将要被分割的字符串的指针,通过此指针来接收将要被分割的字符串(此字符串中包含了将要作为分割表示的字符)。
2..参数sep字符串是指向分割字符集合的指针(可以是多个)。
二、库函数strtok的使用方法
1.strtok会找到下一个标记符,并在此处将标记符替换为'\0',再通过char*类型的指针将'\0'之前的首元素地址返回。(注:此函数会修改原来的字符串,所以strtok函数一般用来切割拷贝的函数)
2.strtok在剪切完一组字符串时会保存这一次的切割位置,当下一次第一个参数传空指针NULL时在上一次切割完的位置继续寻找标识符进行切割。若下一次第一个参数传的不是空指针,则重新切割此次传入的字符串。
3.strtok在再一次剪切被strtok剪切过的字符串时会继续找到下一个标识符替换成'\0'并传回从上一次剪切时替换的'\0'之后的首元素地址。
举例:
库函数strerror(包含在头文件string.h中)
一、库函数strerror的定义:
>此函数是一个报错函数,参数是给定的错误码,不同的错误码有不同的报错内容。
二、库函数strerror的使用方法:
1.传入不同的错误码时有不同的报错效果
如:
2.可以配合erron使用,erron(包含在头文件errno.h中)专门用来记录程序运行时出错的错误码,并将其返回。
一系列字符分类函数(包含在头文件ctype.h中)
例如islower函数,输入传参后是小写字母返回非0数,不是返回0。
两个字符转换函数(包含在头文件ctype.h中)
1.tolower函数可以将英文字符转换成小写
如:
2.toupper函数可以将英文字符转换成大写
如:
库函数memcpy(包含在头文件string.h中)
一、库函数memcpy的定义:
>将source参数向后拿出的num参数大小字节的数据拷贝到参数destination的内存位置。
1.该函数不考虑数据类型。
2.该函数遇到'\0'不会停止拷贝。
二、库函数memcpy的使用方法
如:
1.参数destination传入将拷贝的内存
2.参数source传入将要拷贝的数据
3.参数num传入将要拷贝数据的字节大小
三、模拟memcpy函数的实现
void* My_memcpy(void* dest, void* src, size_t num)
{
assert(dest);
assert(src);//断言防止dest,src为空指针
void* ret = dest;//ret是为了记录并返回拷贝完后数据头起点,让函数更人性化
while (num--)//做一个num次的循环来传递数据
{
*(char*)dest = *(char*)src;//拷贝一字节的数据,注意void类型的指针不能直接解引用,需要用大小都是1字节的char类型指针强制转
dest = (char*)dest + 1;
src = (char*)src + 1;//拷贝完后让两个指针都向后走一字节
}
return ret;//拷贝完num个字节的数据后返回头起点
}
以上是memcpy的模拟实现函数My_memcpy
>注意void类型指针不能直接解引用
>size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数。它是为了方便系统之间的移植而定义的,不同的系统上,定义size_t 可能不一样。size_t在32位系统上定义为 unsigned int,也就是32位无符号整型。在64位系统上定义为 unsigned long ,也就是64位无符号整形。size_t 的目的是提供一种可移植的方法来声明与系统中可寻址的内存区域一致的长度。
四、memcpy函数实现的原理
如下例子
以小端存储为例,在代码运行时arr和arr2的存储结构是这样的:
每一次指针替换的过程是这样的:
以此类推,一直到12字节的数据都被全部修改~
库函数memmove(包含在头文件string.h中)
一、库函数memmove的定义:
>该函数将source参数向后拿出的num参数大小字节的数据拷贝到参数destination的内存位置
二、库函数memmove与memcpy的区别:
在我们使用memcpy拷贝数据的时候,如果拷贝相同区域的数据会不会影响结果呢?
由于每个编译器的memcpy的功能有差别,为了避免歧义我们在这使用My_momcpy来验证:
现在我们由arr首元素地址想arr的第三个元素开始拷贝12字节的数据,发现原本第五个元素应该是3,可是这这却被替换成了1。
现在我们用memmove函数来试一下:
数据并没有出错
由此看来memmove函数和memcpy函数功能相同,但是memmove函数可实现相同区域重叠的数据拷贝,比memcpy更高级。
三、库函数memmove与memcpy的区别的原理:
我们简化一下存储结构直接用4个字节的整型单位来表示:
从此图我们可以看出我们将要替换与被替换的数据区域值为3的这个元素是重叠的
我们先从前向后替换:
我们发现第一次3这个元素被替换成了1
我们发现第二次4这个元素被替换成了2
在最后一次替换时按原来的意愿我们的5元素应当被替换成3,开始3这个元素在第一次替换时变成了1,出现了我们不愿期望的结果
那如何不影响重叠数据之间替换呢?
我们可以从最后一个将要被替换的元素来作为第一个起始元素来开始替换:
我们先将5做为第一个被替换倒着被元素3替换
再将4做为第一个被替换倒叙被元素2替换
最后再将3替换成1,如愿以偿的得到了我们最初想要的数组
那我们什么时候该用正叙替换什么时候该用倒叙替换呢?
按上述例子可以总结出:在拷贝替换时存在重叠的数据区域时,被替换的首元素地址比要做为替换的首元素地址低的情况用正叙,反之用倒叙。
四、模拟memmove函数的实现
由以上规律,我们自主实现memmove函数:
void* My_memmove(void* str1, void* str2,size_t num)
{
assert(str1);
assert(str2);
size_t o = 0;
void* ret = str1;
if (str2 > str1)//被替换的首元素地址比要做为替换的首元素地址低
{
while (o<num)
{
*((char*)str1 + o) = *((char*)str2 + o);//随着o的增长,每一次拷贝都是从前向后依次进行
o++;
}
}
else
{
while (num--)//被替换的首元素地址比要做为替换的首元素地址高
{
*((char*)str1 + num) = *((char*)str2 + num);//当num每一次运行时都会减一从而实现倒叙
}
}
return ret;
}
运行效果如下:
感谢各位的阅读,谢谢大家!