今天我在教几个朋友如何使用C结构体。其中一个问你是否可以从函数返回结构体,我回答说:“不能!你会返回指向动态错误结构的指针。”

来自一个主要做c++的人,我期望不能按值返回结构。在c++中,你可以重载对象的操作符=,使用函数按值返回对象是完全有意义的。然而,在C语言中,你没有这个选项,所以它让我思考编译器实际上在做什么。考虑以下几点:

struct MyObj{
    double x, y;
};

struct MyObj foo(){
    struct MyObj a;
    
    a.x = 10;
    a.y = 10;
    
    return a;
}        

int main () {

    struct MyObj a;
    
    a = foo();    // This DOES work
    struct b = a; // This does not work
      
    return 0;
}    

我明白为什么struct b = a;不应该工作——您不能重载数据类型的operator =。为什么a = foo();编译好了吗?它的意思是不是不是struct b = a;?也许要问的问题是:结合=符号的return语句到底有什么作用?


当前回答

回传结构体没有问题。它将通过值传递

但是,如果结构体包含任何具有局部变量地址的成员呢

struct emp {
    int id;
    char *name;
};

struct emp get() {
    char *name = "John";

    struct emp e1 = {100, name};

    return (e1);
}

int main() {

    struct emp e2 = get();

    printf("%s\n", e2.name);
}

现在,这里的e1.name包含函数get()的本地内存地址。 一旦get()返回,name的本地地址将被释放。 因此,在调用者中,如果我们试图访问该地址,它可能会导致分割错误,因为我们正在尝试一个释放的地址。这很糟糕。

这里是e1。Id将完全有效,因为它的值将被复制到e2.id

因此,我们应该总是尽量避免返回函数的本地内存地址。

任何错误的东西都可以在需要的时候返回

其他回答

struct emp {
    int id;
    char *name;
};

struct emp get() {
    char *name = "John";

    struct emp e1 = {100, name};

    return (e1);
}

int main() {

    struct emp e2 = get();

    printf("%s\n", e2.name);
}

适用于较新版本的编译器。 就像id一样,name的内容被复制到赋值的结构变量中。

回传结构体没有问题。它将通过值传递

但是,如果结构体包含任何具有局部变量地址的成员呢

struct emp {
    int id;
    char *name;
};

struct emp get() {
    char *name = "John";

    struct emp e1 = {100, name};

    return (e1);
}

int main() {

    struct emp e2 = get();

    printf("%s\n", e2.name);
}

现在,这里的e1.name包含函数get()的本地内存地址。 一旦get()返回,name的本地地址将被释放。 因此,在调用者中,如果我们试图访问该地址,它可能会导致分割错误,因为我们正在尝试一个释放的地址。这很糟糕。

这里是e1。Id将完全有效,因为它的值将被复制到e2.id

因此,我们应该总是尽量避免返回函数的本地内存地址。

任何错误的东西都可以在需要的时候返回

#include <stdio.h>

struct emp {
    int id;
    char *name; /* This must point to valid memory, or replace with an array  that holes the data, like this char name[128] */
};

struct emp bad() {
    static char name[] = {'J', 'o', 'h', 'n', '\0'}; /* static enforces this array to be stored globally and not in the local stack which would not be valid after the function returns */
    struct emp e1 = {404, name};
    return (e1);
}

int main() {
    struct emp e2 = bad();
    printf("%s\n", e2.name);
}

据我所知,第一个版本的C只允许返回一个值 可以装进处理器寄存器,这意味着你只能返回一个指针 一个结构体。同样的限制也适用于函数参数。

最近的版本允许传递更大的数据对象,如结构体。 我认为这个功能在80年代或90年代早期已经很普遍了。

然而,数组仍然只能作为指针传递和返回。

结构变量e2地址作为参数被推到被调用栈,值在那里被赋值。实际上,get()返回e2在eax reg中的地址。这类似于引用调用。