C语言:内存重叠

来源:互联网 发布:php和c的区别 编辑:程序博客网 时间:2024/06/03 21:47
内存重叠:拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。

在函数strcpy和函数memcpy都没有对内存重叠做处理的,使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠,或者使用memmove函数进行内存拷贝。
memmove函数对内存重叠做了处理。

面举例一个可能会发生内存重叠的问题:
有n个整数,使前面的各数顺序向后移m个位置,最后m个数变成最前面的m个数。

问题分析:
假设arr为保存n为1-10的十个整数的数组,m=3,
思路为:先将8910(最后m个数)保存在另一个临时数组中,再将1-7整体向右(后)移动3(m)位,最后将保存后m个数的临时数组放到最前面。
我们期望实现的结果为89101234567,
我们在将1-7向后移动的过程中,可能会出现内存重叠问题:我们由左至右移动数据,m=3,我们arr[0]处的1移动到arr[0+3](arr[3])处,将arr[1]处的2移动到arr[1+3](即arr[4])处,依次类推向后移动,但是我们忽略掉了一个问题,当我们在将arr[3]处的数移动到arr[6]处时,此时的arr[3]已被修改为了1,以此类推,移动完后的结果为:1231231,并不是我们期望的1234567.这就是在移动的过程中发生了内存重叠问题。

解决方案:如果拷贝的目的地址在源地址范围内且是从低地址拷贝到高地址,那么应从被拷贝的数据的最后一位倒着依次向后移,如果是从高地址向低地址拷贝,那么应从被拷贝的数据的第一位顺着依次向前移。
所以我们可以在拷贝的过程中从右至左的移动数据,arr[6]移动到arr[9],arr[5]移动到arr[8],arr[4]移动到arr[7]依次类推,移完整个数组,在这样的移动过程中即使之前的数据被覆盖了也无妨,因为此时我们已经实现了原数据的移动。

#include#includevoid Move(int *arr,int n,int m){if(arr==NULL || n<=0 || m<0 || n{return ;}int *p = (int *)malloc(m*sizeof(int));//动态申请内存,保存后m个数int i;for(i=0;i{p[i] = arr[n-m+i];//把后m个数移出来}for(i=n-m-1;i>=0;i--)//为防止内存重叠,从后开始移{arr[i+m] = arr[i];//把数往后推m位}for(i=0;i{arr[i] = p[i];//把后m个变成前面m个数}free(p);//释放动态内存}void Show(int *arr,int len){for(int i=0;i{printf("%d ",arr[i]);}printf("\n");}int main(){    int arr[10] = {1,2,3,4,5,6,7,8,9,10};    Show(arr,sizeof(arr)/sizeof(arr[0]));//打印移动前的数据    Move(arr,sizeof(arr)/sizeof(arr[0]),3);    Show(arr,sizeof(arr)/sizeof(arr[0]));//打印移动后的数据return 0;}

memcpy和memmov函数原型和区别
  •   1.memmove

    函数原型:void *memmove(void *dest, const void *source, size_t count)

    返回值说明:返回指向dest的void *指针

    参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数

    函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

  •   2.memcpy

    函数原型:void *memcpy(void *dest, const void *source, size_t count);

    返回值说明:返回指向dest的void *指针

    函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。