從memcpy到memmove,記憶體函式拷貝與記憶體重疊問題(重點內容)
阿新 • • 發佈:2021-01-31
有一個關於拷貝的問題,假如有這樣一個字串
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;
}
此時再來輸出結果就正常了