关于内存重叠问题,以一个题为例:
有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数。
我们通常会遇到以下四种情况:
(1)如下图,将10个数中后3个数变为最前面3个数,前面各数顺序向后移动3个位置。由图可以看出,我们在移动时,先将后面3个数存到一个临时数组中,然后将剩下的数必须先从7开始依次向后移动3个位置,因为存在内存重叠问题,下图中蓝色部分为内存重叠部分,剩下的数都移动完之后,再将临时数组中存储的最后面3个数依次移动到最前面。
代码如下:
# include<stdio.h>
# include<stdlib.h>
void Move(int *arr,int n,int m)
{
if(m<=0 || n<=0 || m>=n)
{
return ;
}
int * brr = (int *)malloc(m*sizeof(int));
int i;
for(i=0;i<m;i++)//将后面的数据移到新的内存区域
{
brr[i] = arr[n-m+i];
}
for(i=n-m-1;i>=0;i--)//数据后移,注意方向
{
arr[i+m] = arr[i];
}
for(i=0;i<m;i++)
{
arr[i] = brr[i];
}
free(brr);
}
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
Move(arr,10,3);
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}

(2)如下图,将10个数中最前面3个数变为最后面3个数,使后面各数顺序向前移动3个位置。由图可以看出,我们在移动时,先将前面3个数存到一个临时数组中,然后将剩下的数必须先从4开始依次向前移动3个位置,因为存在内存重叠问题,下图中蓝色部分为内存重叠部分,剩下的数都移动完之后,再将临时数组中存储的最前面3个数依次移动到最后面。
代码如下:
# include<stdio.h>
# include<stdlib.h>
void Move(int *arr,int n,int m)
{
if(m<=0 || n<=0 || m>=n)
{
return ;
}
int * brr = (int *)malloc(m*sizeof(int));
int i;
int j;
for(i=0;i<m;i++)//将前面的数据移到新的内存区域
{
brr[i] = arr[i];
}
for(i=m;i<n;i++)//数据前移,注意方向
{
arr[i-m] = arr[i];
}
for(i=n-m,j=0;i<n,j<m;i++,j++)
{
arr[i] = brr[j];
}
free(brr);
}
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
Move(arr,10,3);
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}

(3)如下图,将10个数中后5个数变为最前面5个数,前面各数顺序向后移动5个位置。由图可以看出,我们在移动时,先将后面5个数存到一个临时数组中,然后将剩下的数依次向后移动5个位置,现在这种情况我们可以先移动1,也可以先移动5,因为这种情况不存在内存重叠的问题,剩下的数都移动完之后,再将临时数组中存储的最后面5个数依次移动到最前面。
从5开始移动的代码和(1)中的相同,这里给出从1开始移动。
代码如下:
# include<stdio.h>
# include<stdlib.h>
void Move(int *arr,int n,int m)
{
if(m<=0 || n<=0 || m>=n)
{
return ;
}
int * brr = (int *)malloc(m*sizeof(int));
int i;
int j;
for(i=0;i<m;i++)//将后面的数据移到新的内存区域
{
brr[i] = arr[n-m+i];
}
for(i=0;i<m;i++)//数据后移,注意方向
{
arr[i+m] = arr[i];
}
for(i=0,j=0;i<n,j<m;i++,j++)
{
arr[i] = brr[j];
}
free(brr);
}
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
Move(arr,10,5);
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}

(4)如下图,将10个数中最前面5个数变为最后面5个数,使后面各数顺序向前移动5个位置。由图可以看出,我们在移动时,先将前面5个数存到一个临时数组中,然后将剩下的数依次向后移动5个位置,现在这种情况我们可以先移动6,也可以先移动10,因为这种情况不存在内存重叠的问题,剩下的数都移动完之后,再将临时数组中存储的最前面5个数依次移动到最后面。
同样从6开始移动的代码和(2)的代码相同,这里给出从10开始移动的代码。
代码如下:
# include<stdio.h>
# include<stdlib.h>
void Move(int *arr,int n,int m)
{
if(m<=0 || n<=0 || m>=n)
{
return ;
}
int * brr = (int *)malloc(m*sizeof(int));
int i;
int j;
for(i=0;i<m;i++)//将前面的数据移到新的内存区域
{
brr[i] = arr[i];
}
for(i=n-m;i<n;i++)//数据前移,注意方向
{
arr[i-m] = arr[i];
}
for(i=n-m,j=0;i<n,j<m;i++,j++)
{
arr[i] = brr[j];
}
free(brr);
}
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
Move(arr,10,5);
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
