void* memcpy(void* destination, const void* source, size_t num);
\0
的时候并不会停下来使用方法:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello world!";
int arr3[10] = { 0 };
int arr4[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int i = 0;
memcpy(arr1, arr2, 12);
memcpy(arr3, arr4, 16);
printf("%s\n", arr1);
for (i = 0; i < 10; i++)
{
printf("%d ", arr3[i]);
}
return 0;
}
如果源头和目的地是同一块内存它进行拷贝的时候会出现覆盖的情况。
如:
#include
#include
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int i = 0;
memcpy(arr + 2, arr, 16);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
可以看到它并没有如我们预期的输出来输出结果,我们预期的结果应该是:1 2 1 2 3 4 7 8 9 10
可是memcpy拷贝的时候会覆盖,而C语言对memcpy的标准是只要能实现拷贝即可,不考虑同一块内存拷贝会覆盖的情况,这种情况是由另一个函数来处理。
当然有些编译器对memcpy函数的实现是有优化过的,目前我个人知道的编译器是VS它是对memcpy有优化的,如果拷贝的是同一块内存它不会覆盖,而是如预期的那样进行拷贝。
#include
void* my_memcpy(void* dest, const void* src, unsigned int count)
{
assert(dest && src);//断言
void* temp = dest;//temp保存dest的起始地址
while (count--)
{
*(char*)dest = *(char*)src;//复制src的内容到dest
++(char*)dest;//下一个字节的拷贝
++(char*)src;
}
return temp;//返回dest起始地址
}
void* my_memcpy(void* dest, const void* src, unsigned int count);
参数一:
void* dest
dest设置成空类型,因为空类型可以接收任何大小的数据,但是有一个缺陷它不能自增或者自减,也不能直接解引用因给它空类型是一个没有具体类型,它不知道它能访问多少个字节,所以使用空类型的时候我们需要强制类型转换。
dest是缓冲区
参数二:
void* src
它的类型和dest一样不过,它和参数一不同的是它被
const
保护起来了,因为它只是被复制也就是说我们只是访问它里面的内容并不需要修改它,所以我们就加一个const
把它保护起来,防止我们不小心对它进行修改参数三:
unsigned int counst
counst是我们要修改多少字节的参数,修改是以字节为单位的,它的类型是
unsigned int
(无符号整整形)也就是说不能出现负数返回类型:void*
返回dest的首地址
assert(dest && src);
这个是用来保证代码的健壮性,assert()
函数是断言,如果传过来的是空指针,那么就是假因为NULL
的值是0,只有两边都为真才不会有提示。
*(char*)dest = *(char*)src;
因为是void* 类型所以我们要强制转换才能解引用进行拷贝操作,而我们要操作的是一个字节所以转为字符型指针最合适。
++(char*)dest;
和上面的同理,要强制类型转换才能进行++和–操作。
void* memmove(void* destination, const void* source, size_t num);
使用方法:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int i = 0;
memmove(arr + 2, arr, 16);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
memmove
和memcpy
的使用方法一样,没什么大区别。
#include
void* my_memmove(void* dest, const void* src, unsigned int count)
{
assert(dest && src);//断言
void* temp = dest;
if (dest < src)//小于src从前向后
{
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else//大于从后向前
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return temp;
}
为了处理同块内存的拷贝,这里我们分为了两种方法。
memcpy用的是从前向后拷贝,所以会出现被覆盖的情况。
那么问题来了,我们什么情况才从前向后拷贝和从后向前拷贝呢?
我们可以以src为分界线,如果dest小于src我们就从前向后,这样就避免了src的内容被覆盖之后被拷贝到dest里面去,如果dest大于src,我们就从后向前。
那有人问如果等于呢?等于的话你从前向后还是从后向前不都一样?
所以按照这个思路我们写成两个拷贝顺序,从后向前我们不用思考了,想在我们只需要思考从后向前拷贝。
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
从后向前我们只需要先得到dest和src末尾的地址就能进行从后向前操作了,count + dest
不就得到了末尾了吗?counst + dest
得到末尾的\0
的地址,但是我们不需要修改\0
所以count + dest
之前我们对count
自减。
后面就不需要dest自减的操作了,因为count
每次减一我们就得到前面一个的地址,当count
减完了,我们也拷贝完了。
int memcmp(const void* ptr1, const void* ptr2, size_t num);
使用案列:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
int main()
{
char arr1[] = "abcz";
char arr2[] = "abcd";
if ( 0 < memcmp(arr1, arr2, 4))
{
printf("大于\n");
}
else if(0 > memcmp(arr1, arr2, 4))
{
printf("小于\n");
}
else
{
printf("等于\n");
}
return 0;
}
#include
int my_memcmp(void* dest, const void* src, unsigned int count)
{
assert(dest && src);//断言
if (!count)
{
return 0;
}
while (--count && *(char*)dest == *(char*)src)
{
++(char*)dest;
++(char*)src;
}
return *(char*)dest - *(char*)src;
}
if (!count)
{
return 0;
}
如果count
是0的话就直接返回0
while (count-- && *(char*)dest == *(char*)src)
{
++(char*)dest;
++(char*)src;
}
当count
个数比较完或者dest不等于src,我们就停止循环。
return *(char*)dest - *(char*)src;
直接返回dest - src,如果它们两相等一定返回0,dest小于src返回的是小于0的值,大于则返回大于0的值。
void *memset( void *dest, int c, size_t count )
memset是以1字节为单位来修改,第二个参数是要修改成什么字符,第三个参数是修改内存个数以1字节为单位
使用案列:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
char arr[10] = { 0 };
int i = 0;
memset(arr, '6', 10);
for (i = 0; i < 10; i++)
{
printf("arr[%d]=%c\n", i, arr[i]);
}
return 0;
}
#include
void* my_memset(void* dest, int a, unsigned int count)
{
assert(dest);//断言
void* temp = dest;//记录dest的首地址
while (count--)
{
*(char*)dest = a;
++(char*)dest;
}
return temp;//返回dest的首地址
}
while (count--)
{
*(char*)dest = a;
++(char*)dest;
}
把a的值给dest,来进行修改,每次修改一个字节就自增一修改下个字节。