【问题标题】:Copy memory address to a memory block将内存地址复制到内存块
【发布时间】: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);

如果我请求一个内存块(使用callocmalloc)然后用我想将这些内存块的地址存储在动态数组中的数据填充它,而不是使动态数组持有此类数据的副本。

总结一下:我定义的动态数组操作是使用memcpy 实现的,目前没有达到预期的效果(虽然复制数据按预期工作)。我希望能够有效地在我的动态数组 any 中保存任意数据类型(数据的副本或内存地址的副本,这当然取决于动态数组操作的方式调用:如果我传递一个指针,数据被复制,但如果我传递一个指针的地址,它的内存地址应该被复制)。

我找到了以下答案:Store pointer address in malloced memory 这似乎是这个问题的答案。但是我并不完全理解它,这也意味着我的动态数组实现需要区分何时使用memcpy 或何时直接赋值。这个问题可以用memcpy以外的其他函数来解决吗?还是我完全错过或不理解的其他东西?我在示例中的推理有什么问题?

抱歉帖子太长,提前致谢!

【问题讨论】:

  • 怎么样:void *buffer = &amp;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(即&amp;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:如果您遵循我在第一条评论中给出的建议,那么您的程序是否按预期工作?那么,两个打印的指针值是相同的。

标签: c pointers memcpy


【解决方案1】:
printf("person address: %p\tptr address: %p.\n", person, ptr);

这里,ptrbuffer 是同一个指针。它是指向指针的指针,而不是存储在buffer 中的指针。

它来自这个声明:

struct Person* ptr = (struct Person*) buffer;

很明显ptrbuffer 是同一个指针,只是类型不同。

你想要的是:

// The cast is not required in C, but I'm keeping it
struct Person **pptr = (struct Person **) buffer;

现在pptr 是一个指向Person 的指针,这正是我们想要的。

我们可以评估*pptr

 printf("person address: %p\tpptr address: %p.\n", (void *) person, (void *) *pptr);

请注意,严格的 ISO C 一致性需要强制转换; %p 转换说明符需要 void * 类型的参数,而不仅仅是任何指针。

如果我们只使用pptr,我们不需要memcpy;我们可以使用以下方式存储值:

*pptr = person;  // instead of memcpy(&pptr, &person, sizeof pptr);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 2021-12-27
    • 2013-08-25
    • 1970-01-01
    • 2020-12-06
    相关资源
    最近更新 更多