在C语言中如何通过引用传递结构体指针

3
请注意以下代码段:

记住以下代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A* a)
{
    a->a = 3;
    a->b = 2;
    a->c = 1;
}
int main()
{
    test = malloc(sizeof(A));
    init(test);
    printf("%d\n", test->a);
    return 0;
}

运行良好!现在想象一下,我想在不返回指向结构体的指针的情况下,在main之外使用malloc函数。我将把malloc放在init中,并传递test地址。但这似乎行不通。

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A** a)
{
    *a = malloc(sizeof(A));
    *a->a = 3;
    *a->b = 2;
    *a->c = 1;
}
int main()
{
    init(&test);
    printf("%d\n", test->a);
    return 0;
}

当我使用指针时,它一直告诉我a(或b/c)不是struct A的成员。

我敢打赌它告诉你的不是那个。实际的错误信息是什么? - melpomene
@melpomene 请求访问非结构体或联合体中的成员'a'。 - Primemaster
3
看吗?它甚至没有提到 struct A。它说你试图使用的东西根本不是一个 struct。(正如下面的答案所解释的那样,你的代码被解析为 *(a->a)a->a 相当于 (*a).a,而 *a 的类型是 A *;也就是说,编译器认为你正在尝试访问指针的成员,这是毫无意义的。) - melpomene
只是提醒一下,C语言中没有传引用的概念,全部都是传值。在这种情况下,你将一个指针按值传递给init函数,在函数内部对其进行解引用和操作。 - yano
4个回答

6
你的问题是操作符优先级问题。 -> 操作符的优先级高于 *(解引用)操作符,因此 *a->a 被读作 *(a->a)。将 *a->a 改为 (*a)->a
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A** a)
{
    *a = malloc(sizeof(A));
    (*a)->a = 3;
    (*a)->b = 2;
    (*a)->c = 1;
}
int main()
{
    init(&test);
    printf("%d\n", test->a);
    return 0;
}

5

你需要添加括号:

void init(A **a)
{
    *a = malloc(sizeof(A)); // bad you don't verify the return of malloc
    (*a)->a = 3;
    (*a)->b = 2;
    (*a)->c = 1;
}

但是这是一个好的习惯:

void init(A **a)
{
    A *ret = malloc(sizeof *ret); // we want the size that is referenced by ret
    if (ret != NULL) { // you should check the return of malloc
        ret->a = 3;
        ret->b = 2;
        ret->c = 1;
    }
    *a = ret;
}

4

出于优先级的原因,您需要编写(*a)->a = 3;


哇,我真的没想到这是一个语法问题。谢谢! - Primemaster

4

虽然这不是你问题的直接答案,但由于我们正在初始化附近,我想指出C11为您提供了更好的语法来初始化结构体:

void init(A **a)
{
    A *ret = malloc(sizeof *ret); // we want the size that is referenced by ret
    if (ret != NULL) { // you should check the return of malloc
        *ret = (A) {3, 2, 1};
        // or
        *ret = (A) { .a = 3, .b = 2, .c = 1 };
    }
    *a = ret;
}

另一个优点是任何未初始化的成员都会被清零。

这里有一个非常有趣和用户友好的文档链接:http://en.cppreference.com/w/c/language/compound_literal。但我想知道它是否创建了一个临时变量,还是仅影响结构体。 - Stargateur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接