繁体   English   中英

c语言实现memmove的问题

[英]Problems with implementing memmove in c

我正在尝试为某个测验实现memmove()函数,因此我动态分配了一块内存,其中 ptr 缓冲区作为交换操作中的临时持有者,并且交换在一个循环中完成。 当我提交此代码时,它给了我 3 个测试用例中的一个错误答案。 当我将交换分成两个 for 循环时,所有情况都会成功。 那么区别是什么呢 ?

  • 同一个循环中交换(一种情况错误):

     uint8_t *my_memmove(uint8_t *src, uint8_t *dst, size_t length) { uint8_t *buffer; buffer = (uint8_t*)reserve_words(length); for (uint8_t i = 0; i < length; i++) { *(buffer+i) = *(src+i); *(dst+i) = *(buffer+i); } return dst; free_words((uint32_t*)buffer); }
  • 交换两个循环(所有案例都成功):

     uint8_t *my_memmove(uint8_t *src, uint8_t *dst, size_t length) { uint8_t *buffer; buffer = (uint8_t*)reserve_words(length); for (uint8_t i = 0; i < length; i++) { *(buffer+i) = *(src+i); } for (uint8_t i = 0; i < length; i++) { *(dst+i) = *(buffer+i); } return dst; free_words((uint32_t*)buffer); }
  • 使用的 Reserve_words 函数(user_defined):

     int32_t *reserve_words(size_t length) { int32_t *ptr; ptr = (int32_t *)malloc(length * sizeof(int32_t)); return ptr; }

这里的问题是 memmove 保证可以使用重叠的内存块。 如果您想查看第一个版本失败的情况,请尝试以下操作:

char str[20]="Hello, World!";
my_memmove(&str[0], &str[1], 13);
puts(str);

输出是:

HHHHHHHHHHHHHH

很容易理解为什么。 每次迭代都会写入下一次迭代要读取的字节。

所以你的第一个版本的my_memmove应该真正被称为my_memcpy ,因为memcpy不能保证与重叠的内存区域一起工作,而memmove就是这样。

  • 第一个版本从源复制到目标,因为它复制到临时数组:如果源和目标数组重叠并且src < dst您将在复制之前覆盖源数组的一部分。 这正是实现memmove()的难点所在
  • 第二个版本分配了一个临时数组,从源复制到它,然后从临时数组复制到目标:没问题,除非你在return语句后free了临时数组,所以有内存泄漏,你可能没有期望为此分配分配内存。
  • 所有复制循环中都有一个错误: i应该定义为size_t ,而不是uint8_t 按照编码,该函数对于长度超过 255 字节的块将失败。
  • 无需分配length字来节省length字节。

memmove()的技巧是测试dst是否指向源数组内部,如果是这种情况,则从源数组的末尾复制到开头。 没有完全可移植的方法来做到这一点,但对于大多数具有平坦地址空间的当前系统,测试if (dst > src && dst < src + length)工作正常。

这是一个简单的实现(请注意,您的原型具有从标准memmove()函数转置的srcdst指针):

uint8_t *my_memmove(const uint8_t *src, uint8_t *dst, size_t length) {
    if (dst > src && dst < src + length) {
        for (size_t i = length; i-- > 0;)
            dst[i] = src[i];
    } else {
        for (size_t i = 0; i < length; i++)
            dst[i] = src[i];
    }
    return dst;
}
  1. 内存泄漏
    return dst;
    free_words((uint32_t*)buffer);

您永远不会调用free_words因为它会更早返回。

  1. 当您在一个循环中复制并且内存位置重叠时,您的算法将覆盖数据并且该函数将不起作用。

  2. 这个缓冲区完全没用,它是错误编程的一个例子

  3. 函数应该获取并返回void *指针。

  4. 如果赋值的一侧是 (void *),则不必强制转换指针

void *mymemmove(void *dest, void *src, size_t size)
{
    void *saveddest = dest;
    unsigned char *ucdest = dest, *ucsrc = src;
    if(dest && src && size)
    {
        if(dest < src)
        {
            while(size--)
            {
                *ucdest++ = *ucsrc++;
            }
        }
        else if(src < dest) //this if to avoid copy if dest == src (not needed)
        {
            ucdest += size - 1; ucsrc += size - 1;
            while(size--)
            {
                *ucdest-- = *ucsrc--;
            }
        }
    }
    return saveddest;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM