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)当源内存的首地址小于目标内存的首地址时,实行反向拷贝。

文章有参考其他文章,如果有错误还请指出。

猜你喜欢

转载自blog.csdn.net/cyy_0802/article/details/80293961