好吧,我试图将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;
}
顺便说一句,我是一个指针的新手,所以如果有一些错误,不要惊讶。 我做错了什么?
答案 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
,则可用索引将从0
到num-1
。在您的循环中,i
会因0
到num
而异,这要归功于条件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个字节。如果它听起来很技术,请不要太担心,当你达到一个非常低的水平时,它会很重要;)