1. 程式人生 > 其它 >從memcpy到memmove,記憶體函式拷貝與記憶體重疊問題(重點內容)

從memcpy到memmove,記憶體函式拷貝與記憶體重疊問題(重點內容)

技術標籤:memcpymemmovec語言c語言資料結構

有一個關於拷貝的問題,假如有這樣一個字串

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;
}

此時再來輸出結果就正常了