C語言中的記憶體重疊
阿新 • • 發佈:2018-11-15
首先我們先看這樣一道題:有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)當源記憶體的首地址小於目標記憶體的首地址時,實行反向拷貝。
文章有參考其他文章,如果有錯誤還請指出。