【发布时间】:2021-01-25 17:19:53
【问题描述】:
我已经很长时间没有使用 C 编程了,最近决定重新使用它。我发布这个问题是因为我无法完全理解 memcpy 函数。我希望能够将内存地址复制到一块内存中。例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[255];
char last_name[255];
short age;
};
int main(void) {
struct Person* person = calloc(1, sizeof(struct Person));
strcpy(person->name, "John");
strcpy(person->last_name, "Travolta");
person->age = 66;
void* buffer = calloc(1, sizeof(struct Person*));
// This won't copy the address of `person` into buffer.
// I don't understand why.
memcpy(buffer, &person, sizeof(struct Person*));
// If I want to allocate and copy the contents where `person`
// is pointing to that works absolutely fine:
//
// void* buffer = calloc(1, sizeof(struct Person));
// memcpy(buffer, person, sizeof(struct Person));
//
// But that's not what I want. I don't want a copy of the data.
// I want a copy of `person`, NOT a copy of the data where `person`
// is pointing to.
struct Person* ptr = (struct Person*) buffer;
printf("person address: %p\tptr address: %p.\n", person, ptr);
return 0;
}
我已将其编译为:gcc -Wall test-ptr.c -o test-ptr。当我运行它时,我期待printf 给我完全相同的地址。然而,这就是我得到的:
person address: 0x800a40000 ptr address: 0x800644008.
现在是上述问题的一些背景知识。为什么要将内存地址复制到内存块中?仅出于学习目的,我完全从头开始实现动态数组数据结构。它的界面是:
struct DynamicArray new_dynamic_array(size_t element_size);
void* da_get_nth(struct DynamicArray* da, size_t i);
void da_append(struct DynamicArray* da, void* element);
void da_insert(struct DynamicArray* da, void* element, size_t i);
void* da_delete(struct DynamicArray* da, size_t i);
如果我请求一个内存块(使用calloc 或malloc)然后用我想将这些内存块的地址存储在动态数组中的数据填充它,而不是使动态数组持有此类数据的副本。
总结一下:我定义的动态数组操作是使用memcpy 实现的,目前没有达到预期的效果(虽然复制数据按预期工作)。我希望能够有效地在我的动态数组 any 中保存任意数据类型(数据的副本或内存地址的副本,这当然取决于动态数组操作的方式调用:如果我传递一个指针,数据被复制,但如果我传递一个指针的地址,它的内存地址应该被复制)。
我找到了以下答案:Store pointer address in malloced memory 这似乎是这个问题的答案。但是我并不完全理解它,这也意味着我的动态数组实现需要区分何时使用memcpy 或何时直接赋值。这个问题可以用memcpy以外的其他函数来解决吗?还是我完全错过或不理解的其他东西?我在示例中的推理有什么问题?
抱歉帖子太长,提前致谢!
【问题讨论】:
-
怎么样:
void *buffer = &person;而不是malloc/memcpy。这[可能]是你想要的。或者,根据您拥有的 大部分 代码,改为:struct Person** ptr = buffer; printf("person address: %p\tptr address: %p.\n", person, *ptr);(注意双星指针)。 -
我相信你必须把
struct Person* ptr = (struct Person*) buffer;这一行改成struct Person* ptr = *(struct Person**) buffer;这是因为buffer指向一个指向struct Person的指针。 -
"这不会将
person的地址复制到缓冲区中。" -- 变量person的类型为struct Person *。因此person(即&person)的地址具有struct Person **类型。您是否真的要将这样的双指针复制到buffer,这会使buffer成为三指针? -
@N001:您在上一条评论中的解释是正确的。但是,您在代码
This won't copy the address of person into buffer. I don't understand why.中的注释似乎具有误导性,因为您不是在复制/不尝试将person的地址复制到buffer,而是复制值的person。当您引用指针的地址时,这通常意味着指针在内存中的位置,而不是它所保存的值(这也是一个地址)。 -
@N001:如果您遵循我在第一条评论中给出的建议,那么您的程序是否按预期工作?那么,两个打印的指针值是相同的。