1. 程式人生 > >C語言中的記憶體重疊

C語言中的記憶體重疊

首先我們先看這樣一道題:有n個整數,使前面各數順序向後移m個位置,最後m個整數變成最前面m個數,見如下圖,寫一函式實現以上功能,在主函式中輸入n個整數和輸出調整後的n個數。


我們先來分析一下;

有一下兩種情況,(1)後面的數移到前面;(2)前面的數移到後面。


1中反向拷貝會出現記憶體重疊問題情況


3中正向拷貝會出現記憶體重疊問題情況


2的情況如下圖,4和其類似。


程式程式碼為:

void Move(int *arr, int n, int m)//n表示陣列長度,m表示需要移到的後半段的資料長度
{
    if(arr ==NULL || n <= 0 || m < 0 || n < m)//首先是判斷滿足題目的條件
    {
       return;
    }
    int *p =(int *)malloc(m * sizeof(int));//建立動態記憶體,將後m個數據複製過去
    int i;
    for(i = 0; i< m; i++)
    {
       p[i] = arr[n- m + i];
    }
    for(i = n - m - 1; i >= 0;i--)//將前面(n-m)個數據向後移  (解決方案)
    {
       arr[i + m] =arr[i];
   }
for(i = 0; i< m; i++)//將後m個數據複製到前面 { arr[i] =p[i]; } free(p);//釋放記憶體p }
在上面藍色段的過程就有可能出現記憶體重疊問題,看下面程式碼:
for(i = 0; i < n -m; i++)
{
    arr[i + m] =arr[i];
}
如果上面程式碼改為紅色程式碼,程式執行結果會是:1 2 3 1 2 3 1 2 3 1

還有這種寫法;

#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
void Move1(int * arr,int n,int m)//n表示陣列長度,m表示需要移到的後半段的資料長度
{
	assert(arr != NULL);
	int i;
	int j = 0;
	int *q = (int *)malloc(n*sizeof(int));
	for (i = (n - m); arr[i] != '\0'; i++)
	{
		q[j] = arr[i];
		j++;
	}	
	for (i = 0; i < (n - m); i++)
{
	q[j] = arr[i];
	j++;
}
	q[j] = '\0';
	for (j = 0; q[j] != '\0';j++)
	{
		printf("%d", q[j]);
	}
}
int main()
{
	int arr[11] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10 };
        Move1(arr,10,6); } 

分析錯誤3:a[0]複製到a[3]過程中,將原來a[3]的值覆蓋,後面依次覆蓋a[4]、a[5]…。

記憶體重疊問題列舉:當陣列進行拷貝的時候,如果是在同一個陣列內拷貝,就有可能出現記憶體重疊的問題。

void Move2(int *des, int *src, intlen)//從src拷貝到des,len是需要拷貝的資料個數
    for(int i =0; i < len; i++)
    {
       des[i] =src[i];
    }
}
void Show(int *arr, int len)
{
    for(int i =0; i < len; i++)
    {
       printf("%d", arr[i]);
    }
   printf("\n");
}
int main()
{
   //(1)從一個數組拷貝到另一個數組,ok
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    intbrr[10];
    Move2(brr,arr, 10);
    Show(arr,sizeof(arr) / sizeof(arr[0]));
    Show(brr,sizeof(brr) / sizeof(brr[0]));

   //(2)記憶體重疊1,ok
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    Move2(&arr[0], &arr[3], 7);
    Show(arr,sizeof(arr) / sizeof(arr[0]));

   //(3)記憶體重疊2,error
intarr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; Move2(&arr[3], &arr[0], 7); Show(arr,sizeof(arr) /sizeof(arr[0])); return 0; }
上面程式的執行結果分別是:
(1) 1  2  3  4  5  6  7  8  9 10
(2) 4  5  6  7  8  9 10 8  9 10

(3) 1  2  3  1  2  3  1  2  3  1

總結: 如何判斷有記憶體重疊問題?看地址,看目標地址和源地址。
(1)當源記憶體的首地址大於目標記憶體的首地址時,實行正向拷貝;

(2)當源記憶體的首地址小於目標記憶體的首地址時,實行反向拷貝。

文章有參考其他文章,如果有錯誤還請指出。