使用malloc从内存分配中堆积损坏:为什么会发生?

时间:2012-10-07 17:50:31

标签: c++ c pointers memmove

好吧,我试图将memmove作为编程练习来实现,当我尝试使用malloc时,我在memmove函数中遇到了内存访问冲突。这是功能:

//Start

void* MYmemmove (void* destination, const void* source, size_t num) { 

    int* midbuf = (int *) malloc(num); // This is where the access violation happens.
    int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
    int* refsrc = (int *) source; // Same, except with source
    for (int i = 0;num >= i;i++) { 
        midbuf[i] = *(refsrc + i); // Copy source to midbuf
    }
    for (int i = 0;num >= i;i++) { 
        refdes[i] = *(midbuf + i); // Copy midbuf to destination
    } 
    free(midbuf); // free midbuf 
    refdes = NULL; // Make refdes not point to destination anymore
    refsrc = NULL; // Make refsrc not point to source anymore
    return destination;
}

顺便说一句,我是一个指针的新手,所以如果有一些错误,不要惊讶。 我做错了什么?

7 个答案:

答案 0 :(得分:4)

请注意其他建议!答案取决于您的memmove将如何使用。其他答案表明你应该将malloc调用更改为int的大小。但是,如果您的memmove函数将用于表示“移动此数量的字节”,那么实现将是错误的。我会改用char *,因为它可以一次解决几个问题。

此外,int通常为4个字节,char通常为1个字节。如果您收到的void*地址不是字对齐的(不是4字节的倍数),则会出现问题:要复制非字对齐的int,您将不得不进行多次读取和昂贵的位掩蔽。这是低效的。

最后,发生了内存访问冲突,因为您每次都在增加midbuf int指针,并且一次向前移动 4个字节。但是,您只分配了num bytes ,因此最终会尝试访问已分配区域的末尾。

/** Moves num bytes(!) from source to destination */
void* MYmemmove (void* destination, const void* source, size_t num) { 

    // transfer buffer to account for memory aliasing
    // http://en.wikipedia.org/wiki/Aliasing_%28computing%29
    char * midbuf = (char *) malloc(num); // malloc allocates in bytes(!)
    char * refdes = (char *) destination;
    char * refsrc = (char *) source;

    for (int i = 0; i < num; i++) { 
        midbuf[i] = *(refsrc + i); // Copy source to midbuf
    }

    for (int i = 0; i < num; i++) { 
        refdes[i] = *(midbuf + i); // Copy midbuf to destination
    } 

    free(midbuf); // free midbuf
    // no need to set the pointers to NULL here.
    return destination;
}

通过逐字节复制,我们避免了对齐问题,以及num本身可能不是4字节的倍数的情况(例如3,因此int对于该移动而言太大)。

答案 1 :(得分:3)

用malloc替换带有malloc的字符串:

int* midbuf = (int *) malloc(num*sizeof(int)); 

问题是你没有分配int num元素而是num字节。

答案 2 :(得分:1)

int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) { 
    midbuf[i] = *(refsrc + i); // Copy source to midbuf
}

malloc只有num个字节,但在循环中,您尝试复制num int个。由于int通常需要多个字节,因此您正在访问越界。

答案 3 :(得分:0)

内存访问冲突?

您正在尝试访问您无权访问的内存。也许您有一个空指针或指针指向另一个程序或代码段。

答案 4 :(得分:0)

问题在于,您将num个字节标记为midbuf,然后将num个字体复制到其中。由于int大于大多数平台上的字节,因此存在问题。将您的malloc更改为num*sizeof(int),您将不会遇到此问题。

答案 5 :(得分:0)

有两个问题需要考虑

<强> 1。记忆空间

(前提是MYmemmove执行自定义实施以移动ints,如问题所示)

    int* midbuf = (int *) malloc(num * sizeof(int));

malloc基于字节,将分配 num 个字节。 int *是指向ints的指针。含义midbuf[x]将从midbuf + sizeof(int)*x访问内存。您想要分配 num ints(int的大小取决于体系结构,通常为4或2个字节)。因此malloc(num * sizeof(int))

<强> 2。数组索引

    for (int i = 0;num > i;i++) { 
C(和C ++)数组中的

是基于0的,即第一个索引是0。你做得对。但这也意味着如果您保留 num ints,则可用索引将从0num-1。在您的循环中,i会因0num而异,这要归功于条件num >= i,这意味着您将访问num+1项。因此num > i(或i < num)会更好for条件。

答案 6 :(得分:-1)

#include <stdlib.h>  // did you included this?


void* MYmemmove (void* destination, const void* source, size_t num) { 

    char *Source = source, *Destination = destination;
    char *Middle = malloc( sizeof(char) * num );    // midbuf

    for (int i = 0; i < num ; i++) { 
        Middle[i] = Destination[i]; // Copy source to midbuf
    }
    for (int i = 0; i < num ; i++) { 
        Destination[i] = Middle[i]; // Copy midbuf to destination
    }

    free(Middle);                   // free memory allocated previously with malloc
    return destination;
}

可能会发生Acces违规,因为您没有包含malloc所需的库(如果您忘记了函数定义,标准c不会在您的脸上抛出错误)。您不需要将指针标记为NULL,因为C中没有垃圾收集(指针只是指针。指向内存中的某个点,而不是内存本身)。

想想像

这样的指针

指针的地址 0x1243 0x4221 目的地 - &gt; {某种数据}

目的地= 0x1243 *目的地=当前在地址0x4221

的任何值

您也不能索引void指针。您必须先将它们转换为某种类型,以便编译器知道它们需要多少偏移量。

目的地[x] = *(目的地+ x)

char是1个字节,因此char指针实际上会被x个字节移动,但是int是4个字节,int指针将被移动4 * x个字节。如果它听起来很技术,请不要太担心,当你达到一个非常低的水平时,它会很重要;)