将结构指针传递给两个函数,然后调用 malloc

Passing struct pointer to two functions and then calling malloc

我的主要功能中有一个结构。我将该指针传递给另一个函数,该函数执行一些操作,如果满足条件,它将它传递给另一个函数以进行填充。返回主函数时,t 结构包含 none 复制到其中的数据 mydata

typedef struct _t {
    int one;
    int two;
    int three;
    int four;
} T;

void second(T *t) {
    t = malloc(20);
    memcpy(t, mydata, 20);
}

void first(T *t) {
    second(t);
}

int main() {
    T t;

    first(t);
}

我需要在这里使用双指针吗?如果 t 的地址是 0x1000 并且我将它传递给 first() 那么引用 t 不就是 0x1000 吗?就像我将指针传递给 second()?

在这个回答中,我假设,由于未显示的原因,您实际上需要进行动态内存分配。如果不是这种情况,则唯一需要进行的更改是将 first(t); 替换为 first(&t);,并删除 t = malloc(20);.


要解决的第一个问题是 main 中的 t 应该具有类型 T *,而不是 T。您正在进行动态内存分配,并且似乎想将该指针存储在 t 中,因此您需要:T *t;.

第二个问题是您想要在 main 中操作 t 的值,但将其按值传递给 first。相反,您需要将指向 t 的指针传递给 firstfirst(&t);.

修复这两个问题,您现在将指向 T&t 的类型)的指针传递给 firstsecond,因此您需要将他们的签名分别更改为 void first(T **t)void second(T **t).

应用这两项更改,并进行一些小的样式调整,我们得到:

typedef struct T {
    int one;
    int two;
    int three;
    int four;
} T;

void second(T **t_ptr) {
    *t_ptr = malloc(20);
    memcpy(*t_ptr, mydata, 20);
}

void first(T **t_ptr) {
    second(t_ptr);
}

int main() {
    T *t;

    first(&t);
}

另一件遗漏但需要添加的事情是检查 malloc 是否成功,但我没有将其添加到上面的代码中。

此外,您在问题中显示的内容不应该编译;您正在将结构传递给接受指针的函数。

您的问题对于新的 C 开发人员来说很常见。实际上你有两个。

第一个问题是您按值传递结构。 first 函数被声明为接收指向 T 的指针,但您传递的是 t 而不是 &t (这是 t 的地址 - 这就是当一个函数接受一个指针时你想要)。

但是还有一个问题,即使您按照上面的建议更改代码,它仍然无法正常工作。 second 使用 malloc 分配内存。该函数接收 T 作为指针 T *t。您将 malloc 的输出分配给 t,实际上覆盖了 t 指向的内容(如果之前分配了 t,您将在此处泄漏内存)。

您可以在下面看到您想要的正确代码。

typedef struct _t {
    int one;
    int two;
    int three;
    int four;
} T;

/* Make sure we have some data to initialize */
T mydata = {0};

/* 
We take a pointer to a pointer and change what the external pointer points to. */
In our example when this function is called *ppt is NULL 
and t is a pointer to t in main() 
*/ 
void second(T **ppt) {
    /* 
     We never calculate the size of structures by hand. It can change depending on 
     OS and architecture. Best let the compiler do the work.
    */
    *ppt = (T*)malloc(sizeof(T));
    memcpy(*ppt, &mydata, sizeof(T));
}

void first(T **ppt) {
    /* Make sure we don't leave dangling pointers. */
    if (NULL != *ppt)
        free(*ppt);
    second(ppt);
}

int main() {
    
    T *t = NULL; /* A pointer to our data */

    /*
     We pass a pointer to our pointer so that the function can change the value it 
     holds
    */
    first(&t);

    /* Always do an explicit return if the type of the function is not void */
    return 0;
}

如何理解正在发生的事情:

首先,我们将 t 声明为指向保存类型 T 的内存的指针,我们确保将指针初始化为指向 NULL(这是一种约定,意味着指针不是已初始化)。

我们有一个函数可以使用 malloc 为我们分配内存。 malloc 从堆中分配内存,returns 该内存的地址。 (实际上,指针只是一个在内存中保存地址的变量)。我们想将该地址放在 main() 中声明的 t 中。为此,我们需要将 t 的地址传递给分配函数,以便对其进行修改。为此,我们使用 address of 运算符 - &。这就是为什么我们这样调用函数 first(&t).

我们的分配函数接受一个指向指针的指针。这是因为我们要更改 t 指向的地址。所以我们将参数声明为T **ppt。它保存着指针*t在main中的地址。在函数中我们解引用指向指针得到我们要分配地址的原始指针 malloc returns.