memcpy函数的含义、用法和模拟实现: 首先,memcpy函数是用于复制拷贝一个字符串或者一串数字等等不确定的函数:
从一个memcpy函数编写作者角度来看,?由于传入的地址类型是未知的,不清楚到底是用于拷贝字符串还是数字,因此不知道是复制1个字节还是4个字节还是多少个字节,所以用无定形指针void*接收地址,之后便于强制类型转换来进行拷贝,第一个指针dest代表目标地址,也就是需要拷贝到该地址处,sorc代表需要被拷贝的起始地址,由于不需要被改变所以用const来修饰sorc指针,最后一个num是接收需要拷贝的总字节数,一般调用的时候调用sizeof运算符计算大小来传入。
接下来是模拟实现的源代码:
从图中可以看出来我首先将无定形指针转换成char*类型指针然后赋值给字符型指针p记录赋值前的dest首地址,由于dest在后面会向后增加跳转到后面的地址,于是再赋值前先记录dest首地址,便于之后返回一个地址,这样子复制的时候是一个字节一个字节的进行复制,就可以不用理会是什么类型的指针。然后调用循环结构进行num次循环,也就是num个字节的循环,将dest和sorc指针强制类型转换成char*类型再解引用得到该地址下的内容进行赋值,由于dest和sorc指针都是无定形指针,不能直接进行dest++或者sorc++,需要将其强制转换成char*类型的指针进行+1然后跳过这一个字节继续赋值,最后返回dest的首地址,前面提到过了dest会向后增加所以此时的p就对应了dest的首地址用于返回。 所以举个例子来使用memcpy函数:
这里可以看到字符串A对应12345678,而字符串B对应hello world,在my_memcpy函数中,传入第一个元素A,也就是A字符串的首元素地址,再传入B字符串首元素地址,接着调用sizeof运算符来计算需要赋值的字节大小,可以看到我将B字符串的大小传进去了,也就是"hello world\0"(包括了\0)的字节数,也就是12个字节,然后打印字符串A就可以得到"hello world": memmove函数的含义、用法和模拟实现: 首先memmove函数和memcpy函数有相似之处,他们用法差不多而且几乎一模一样,但是memmove函数功能更加全面,并且可以避免拷贝区域重叠的时候拷贝出现错误,接下来看模拟实现的memmove的源代码: 可以看到memmove函数和memcpy函数传入的都是void*类型,而且传入的元素一模一样,但是实现的源代码形式不一样:
可以看到这里将dest转换成char*记录dest首地址是跟memcpy一样的,然后这里有区别的是分了两个方向进行拷贝,分别是dest地址大于sorc地址和其他, 为什么要这样做呢?
原因是如果我在同一个数组里面进行拷贝,第一个元素传入的是A数组的首地址,然后第二个元素传入A数组向后加4的地址,然后拷贝长度为6,也就是说第一个元素的第4、5、6元素和第二个元素B的首元素地址和向后两个长度重合了,那这个时候就分两种情况
这个时候A是目标地址,B是需要被拷贝过去的地址,如果这个时候将B拷贝过去A的话如果从B的第一个元素开始向前拷贝就可以实现, 但是如果是A在B的位置,而B在A的位置:
这个时候,B是源地址,即需要被拷贝地址,而A是目标地址,你需要拷贝过去的地址,你再按照前面的那个方法将B从开头向后进行拷贝到A处,你会发现B与A重叠部分会出现问题,在你拷贝B的向后第五个和第六个地址时候,你从A的角度来看此时A的第一个和第二个地址内容存放的是B一开始第一个和第二个地址里面的内容,此时原来B地址的第五第六个地址对应的内容被覆盖了不能被拷贝,所以要用方法二:即从后往前拷贝,即从B的第六、第五、再到第四这样依次倒序拷贝到A的第六、第五、第四...这样子才能避免刚刚的问题。 此时就分为dest地址在sorc前还是后,即回到刚刚的那个问题为什么要区分dest和sorc地址大小。当然了,如果两个地址以及对应拷贝长度没有重叠,那么从后往前或者从前往后都无所谓,都是可以拷贝过去的,因此就只是分了”dest大于sorc“和”其他“这两种情况。 memmove区别和相同处 从上面可以了解到其实memmove函数和memcpy函数其实 大致是一样的,从起源来说,memcpy函数比较于memmove函数先出现,在后来的发展过程中不断完善后出现了memmove然后解决了以上说到的重叠部分的问题,但也具备memcpy的功能,以此可见在我看来memmove更加好用。都是要包含头文件<string.h> ?
?
|