gpt4 book ai didi

不使用 memcpy() 复制字节

转载 作者:行者123 更新时间:2023-12-04 10:47:27 33 4
gpt4 key购买 nike

这是一项家庭作业。我想实现 memcpy()。有人告诉我内存区域不能重叠。其实我不明白那是什么意思,因为这段代码工作正常,但是有内存重叠的可能性。如何预防?

void *mem_copy(void *dest, const void *src, unsigned int n) {
assert((src != NULL) && (n > 0));
int i = 0;
char *newsrc = (char*)src;
char *newdest = (char*)dest;
while (i < n) {
newdest[i] = newsrc[i];
i++;
}
newdest[i]='\0';
return newdest;
}

最佳答案

当源和目标内存块重叠时,如果您的循环从索引 0 开始一个接一个地复制元素,它适用于 dest < source,但不适用于 dest > source(因为您在复制元素之前覆盖了它们),反之亦然。

您的代码从索引 0 开始复制,因此您可以简单地测试哪些情况有效,哪些情况无效。看下面的测试代码;它显示了如何向前移动测试字符串失败,而向后移动字符串却可以正常工作。此外,它还展示了在向后复制时向前移动测试字符串如何正常工作:

#include <stdio.h>
#include <string.h>

void *mem_copy(void *dest, const void *src, size_t n) {
size_t i = 0;
char* newsrc = (char*)src;
char* newdest = (char*)dest;
while(i < n) {
newdest[i] = newsrc[i];
i++;
}
return newdest;
}

void *mem_copy_from_backward(void *dest, const void *src, size_t n) {
size_t i;
char* newsrc = (char*)src;
char* newdest = (char*)dest;
for (i = n; i-- > 0;) {
newdest[i] = newsrc[i];
}
return newdest;
}

int main() {

const char* testcontent = "Hello world!";
char teststr[100] = "";

printf("move teststring two places forward:\n");
strcpy(teststr, testcontent);
size_t length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy(teststr+2, teststr, length+1);
printf("teststr after mem_copy: %s\n", teststr);

printf("\nmove teststring two places backward:\n");
strcpy(teststr, testcontent);
length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy(teststr, teststr+2, length+1);
printf("teststr after mem_copy: %s\n", teststr);

printf("move teststring two places forward using copy_from_backward:\n");
strcpy(teststr, testcontent);
length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy_from_backward(teststr+2, teststr, length+1);
printf("teststr after mem_copy: %s\n", teststr);
}

输出:

move teststring two places forward:
teststr before mem_copy: Hello world!
teststr after mem_copy: HeHeHeHeHeHeHeH

move teststring two places backward:
teststr before mem_copy: Hello world!
teststr after mem_copy: llo world!

move teststring two places forward using copy_from_backward:
teststr before mem_copy: Hello world!
teststr after mem_copy: HeHello world!

因此可以编写一个函数,它决定是从索引 0 开始复制还是从索引 n 开始复制,具体取决于调用者是要向前复制还是向后复制。棘手的事情是找出调用者是向前复制还是向后复制,因为在 srcdest 上的指针算法实际上并不是在每种情况下都允许 if (src < dest) copy_from_backward(...)(参见标准,例如这个 draft):

6.5.9 Equality operators

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object or incomplete types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.

虽然我从来没有遇到过 src < dest 没有给我想要的结果的情况,但如果它们不属于同一个数组,那么以这种方式比较两个指针实际上是未定义的行为。

因此,如果你问“如何防止它?”,我认为唯一正确的答案一定是:“它取决于调用者,因为函数 mem_copy 无法决定它是否可以正确比较 srcdest。”

关于不使用 memcpy() 复制字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44348403/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com