有一个关于拷贝的问题,假如有这样一个字符串
char a[]="hello";
我需要把这个字符串拷进另一个变量中
char a1[10];
好像方法蛮多的,比如strcpy
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a1[10];
char a2[] = "hello";
strcpy(a1, a2);
printf("%s\n", a1);
system("pause");
return 0;
}
这样就完成了转换,但是如果是int?double?
这时候就需要用到内存函数 memcpy
内存函数,顾名思义是从内存方面下手来进行拷贝,简单来说就是一个字节一个字节的进行拷贝
先进行一下演示吧
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a1[10];
int a2[] = { 1, 2, 3, 4, 5 };
memcpy(a1, a2, sizeof(a2));
//第一个是目标,第二个是需要拷贝,第三个是拷贝的多少
for (int i = 0; i < 10; i++)
{
printf("%d ", a1[i]);
}
printf("\n");
system("pause");
return 0;
}
可以看到的是现在通过memcpy可以将int类型的变量进行拷贝,下面来自行模拟一下这个函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//因为是void,所以针对的是任意类型
//size_t就是typedef后的unsigned int无符号整形
void* my_memcpy(void* n, const void* m, size_t size)
{
char* ch_n = (char*)n;
const char* ch_m = (const char*)m;
for (size_t i = 0; i < size; i++)
{
ch_n[i] = ch_m[i];
//ch_m[i]等价于*(ch_m+i)
}
}
int main()
{
char a1[10];
char a2[] = "hello";
my_memcpy(a1, a2, sizeof(a2));
printf("a1转换后输出:%s\n", a1);
int b1[10];
int b2[] = { 1, 2, 3, 4, 5 };
my_memcpy(b1, b2, sizeof(b2));
printf("b1转换后输出:");
for (int i = 0; i < 10; i++)
{
printf("%d ", b1[i]);
}
printf("\n");
double c1[5];
double c2[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
my_memcpy(c1, c2, sizeof(c2));
printf("c1转换后输出:");
for (int i = 0; i < 5; i++)
{
printf("%lf ", c1[i]);
}
printf("\n");
system("pause");
return 0;
}
但同时memcpy有存在着一些问题,即容易出现内存重叠的现象
例如现在有一个数
int a[]={ 1, 2, 3, 4, 5 };
此时内存占用空间是20个字节
此时在前后40个字节中放数据就容易出现内存重叠的问题
例如
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a[] = { 1, 2, 3, 4, 5 };
memcpy(a + 4, a, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
system("pause");
return 0;
}
输出时结果会变成123412341
此时需要选择从后往前拷贝,简单称呼这种重叠为后重叠
但同时也导致了另一种情况
将12345倒着拷贝,会变成45345345
此时需要从前往后拷贝,为前重叠
不重叠则随意拷贝
需要使用memmove来解决内存重叠问题,也就是不同的情况来不同的分析
知道了原理,那就来模拟一下这个函数吧
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void* my_memmove(void* n, const void* m, size_t size)
{
char* ch_n = (char*)n;
const char* ch_m = (const char*)m;
if (ch_n >= ch_m&&ch_n <= ch_m + size)
{
//从后往前拷贝
for (int i = size - 1; i >= 0; i--)
{
//由于下标是从0开始的,所以i需要-1
ch_n[i] = ch_m[i];
}
}
else
{
//从前往后拷
for (size_t i = 0; i < size; i++)
{
ch_n[i] = ch_m[i];
}
}
return n;
}
int main()
{
int a[10] = { 1, 2, 3, 4, 5, 0, 0, 0, 0, 0 };
my_memmove(a +4, a, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
system("pause");
return 0;
}
此时再来输出结果就正常了