首先我们先看这样一道题:有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)当源内存的首地址小于目标内存的首地址时,实行反向拷贝。
文章有参考其他文章,如果有错误还请指出。