字符函数和字符串函数的章节结束了,接下来我们进入到C语言中的内存函数
今天的主角有:memcpy 函数、memmove 函数、memset 函数、memcmp 函数
一 . memcpy 函数
(1)memcpy 函数的使用
这个 memcpy 函数是专用于内存拷贝的,大家是不是觉得很熟悉,我们才刚刚学习过用于拷贝的函数 —— strcpy 函数和 strncpy 函数,那么它们之间有着怎样的区别呢?
我们之前学习的 strcpy 函数、strncpy 函数是专用于字符串之间拷贝字符的,那么今天我们将要学习的 memcpy 函数诸君看到标题也能知道这个是用于内存拷贝的,它是不仅仅局限于拷贝字符串的,而是所有类型都能拷贝,并且,它可没有什么 memncpy,它本身就能对我们拷贝的元素个数进行限制
(1 . 1)对字符串的拷贝:
(1 . 2)对整型的拷贝:
如上图所示,我们的 memcpy 函数的运用还是相当简单的,有着前两期对这一系列函数的讲解,我相信聪明的诸君理解起来都是非常之简单的,轻松拿捏。如果是没有看过前两期的小伙伴,我建议还是可以去看一看的,能够帮助理解
(2)memcpy 函数的模拟实现
咱们这里直接以整型为例:
(2 . 1)使用 if 循环:
看过前两期的朋友我无需多言,在我们的 My_memcpy 内就是进行的一个简单的赋值、前进再循环
大家可以注意到,我们原 memcpy 函数的格式:
它的接收参数和返回值都是 void * 类型的,我们虽然是用整型举例,但我们实质还是模拟实现 memcpy 函数,我们不能只用整型,也得遵循 void * 类型的接收返回,我们这里虽然是整型类型,但是朋友们请注意了,我们在赋值时用的是 char * 的强转,为什么不用 int * 强转呢?这是因为我们这里需要拷贝给的正好是 20 个字节长度,但如果我给你 17 个字节呢?4 次拷贝结束,剩下的 1 个字节如何处理呢?所以我们选用 char * 类型一个字节一个字节的拷贝是一种更加严谨的操作
我们这个:dest = (char*)dest + 1 为什么不写成:(char*)dest ++ 呢?直接一步到位,这一次我们为什么要用这样 “ 原始 ” 的方式呢?因为我们的强转是一种临时操作,在我们强转之后在解引用的时候,dest 已经不是(char*)的类型了,它依旧是(void*)类型。这个时候有同学要问了,那这样呢:++(char*)dest,这种前置 ++ 是会优先运算的,这个 ++ 的时候我们 dest 还是(char*)的类型,但是这样的方式看似可行,是强转后的马上++,但是这样的方法不能保证在所有的编译器上正确运行的。所以我们只能返璞归真,用这种形式
(2 . 2)使用 while 循环:
while 循环我们直接用 num -- 作为循环条件,直至 num 为 0 自动跳出循环,这一点相信诸君不难理解吧
一 . 一 . memcpy 函数不能用于重叠的内存拷贝
什么叫重叠的内存拷贝呢?如下:
具体解析咱们文字不好说,我用画图的方式给大家呈现:
诸君可以看到,当我们拷贝对象和地址有部分重叠时,当我们需要把 “ 3 ” 拷贝到 “ 5 ” 这个位置的是偶,我们的 “ 3 ” 已经不是 3 了,这个时候它已经被 1 替换掉了
有的同学坚信实践是检验真理的唯一标准昂,自己去试了一下发现没有问题啊,怎么这样说呢,那是因为我们特殊的编译环境,VS上的库函数 memcpy 也能实现重叠内存的拷贝,但并不是所有编译器上都能实现,可能在其他编译器就跑不动了呢?在我们C语言的标准规定中是定义memcpy 函数不负责重叠内存的拷贝,非要使用的话,结果是未定义的,所以我们尽量避免用memcpy 函数去进行重叠内存的拷贝,咱们术业有专攻,进行重叠内存拷贝的角色另有人选,那就是我们接下来即将登场的 memmove 函数!
二 . memmove 函数
(1)memmove 函数的使用
memmove 函数的使用格式跟我们之前讲的一系列函数大差不差,没啥新知识点,咱们多的不说少的不唠,直接演示:
大家看,这一个 memmove 函数就能完美执行我们重叠内存的拷贝,这个没有什么好说的点,咱们直接进入下一环节了昂
(1)memmove 函数的模拟实现
解析:memmove 函数的模拟实现有很重要的点,因为我们并不了解 memmove 函数实现的底层逻辑,我们不可能直接一步到位去实现对重叠内存的拷贝,但是我们可以多思考一下,采用逆向思维:当我们需要拷贝的地址在拷贝对象之后我们的内存会被拷贝时覆盖,那我们不妨试试从后往前拷贝,这样子就能巧妙地避开我们被拷贝覆盖的内存
文字不太好理解,我来在图上为诸君解析:
如图所示,我们可以看到我所列举的两种情况:
(1 . 1)情景一:dest 在 sour 之后
这个时候我们从前往后进行拷贝,就会遇到我们使用 memcpy 函数进行重叠内存拷贝时的问题,我再把那张图拿下来大家看一下:
此时我们如果还是执迷不悟依旧要使用从前往后的常规拷贝方式,那么我们的内容一定会被覆盖掉,所以我们应当选择逆向思维从后往前拷贝,大家可以发现此时从后往前就可以很巧妙的避开拷贝时的重叠元素:5 -> 7,4 -> 6,3 -> 5,2 -> 4,1 -> 3
(1 . 2)情景二:dest 在 sour 之前
当我们的拷贝地址在拷贝对象之前的这种情景,我们会发现此时的从后往前拷贝会使我们的重叠内容被覆盖,所以我们在 dest 在 sour 之前的这种情况还是选择从前往后拷贝,这样子我们的内容就不会被覆盖了
三 . memset 函数
memset 函数的使用
如图,我们的 memset 函数是专用于修改字符串中单个字符的函数
memset 函数中有着三个参数,分别是什么含义呢?
void * ptr:我们要修改的字符串中字符的起始地址
int value:修改的目标字符(将原字符改成什么字符,注意:只能修改成单一字符)
size_t:修改字符的个数(注意:只能连续修改字符)
使用格式非常简单,如下图:
四 . memcmp 函数
memcmp 函数的使用
大家是不是觉得有点眼熟哇,之前我们学到过 strcmp 函数和 strncmp 函数,这俩是专用于字符串大小的比较,比较的是对应字符的ASCLL码值的大小是吧,这个 memcmp 函数是用于比较内存中字节块的大小,不仅仅局限于字符串,并且呢它没有 memncmp 的形式,也是自带对比个数限制的
返回值:这个返回值跟我们的 strcmp 函数和 strncmp 函数的C语言规定是一模一样的:
ptr1 > ptr2 返回大于 0 的数;ptr1 < ptr2 返回小于 0 的数;相等则返回 0
(同样,在我们的 VS 中相对应的也只会返回 1、- 1、0,其他编译器可能会有所不对)
(1)整型间的比较:
(2)字符间的比较:
这个 memcmp 函数还是相当简单的,没啥难点,都是我们学过的老朋友了昂,我觉得也不用给诸君过多赘述了,就这样吧,如果有小伙伴有所疑问的话,欢迎在评论区和私信跟我讨论哦
OKK,有关C语言中的内存函数的章节我们就到此为止啦。诸君动动发财的小手,如果此篇文章对你有所帮助的话,不妨点点赞点点关注噢!就这样吧,咱们下期再见!与诸君共勉!!!