11

请耐心等待我,我来自其他语言和新手到 c 并从http://c.learncodethehardway.org/book/learn-c-the-hard-way.html学习它

struct Person {
    char *name;
    int age;
    int height;
    int weight;
};

struct Person *Person_create(char *name, int age, int height, int weight)
{
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->name = strdup(name);
    who->age = age;
    who->height = height;
    who->weight = weight;

    return who;
}

我理解第二个 Person_create 函数返回一个 struct Person 的指针。我不明白是(可能是因为我来自其他语言,erlang,ruby),为什么将它定义为

struct Person *Person_create(char *name, int age, int height, int weight)

不是

struct Person Person_create(char *name, int age, int height, int weight)

还有其他方法可以定义一个函数来返回一个结构吗?

对不起,如果这个问题太基本了。

4

5 回答 5

12

之所以这样定义,是因为它返回一个指向结构的指针,而不是结构。您将返回值分配给 a struct Person *,而不是struct Person

可以返回完整的结构,如下所示:

struct Person Person_create(char *name, int age, int height, int weight)
{
    struct Person who;
    who.name = strdup(name);
    who.age = age;
    who.height = height;
    who.weight = weight;
    return who;
}

但它并不经常使用。

于 2012-05-04T15:52:22.767 回答
4

Person_create函数返回一个指向 a 的指针,struct Person因此您必须将返回值定义为一个指针(通过添加 *)。要了解返回指向结构的指针而不是结构本身的原因,必须了解 C 处理内存的方式。

当您在 C 中调用一个函数时,您会在调用堆栈上为它添加一条记录。调用堆栈的底部是main您正在运行的程序的函数,顶部是当前正在执行的函数。堆栈上的记录包含传递给函数的参数值和函数的所有局部变量等信息。

您的程序可以访问另一种类型的内存:堆内存。这是您使用 分配空间的地方malloc,它没有连接到调用堆栈。

当您从函数返回时,调用堆栈被弹出,与函数调用相关的所有信息都将丢失。如果你想返回一个结构,你有两个选择:在结构从调用堆栈中弹出之前复制结构内部的数据,或者将数据保存在堆内存中并返回一个指向它的指针。逐字节复制数据比简单地返回指针更昂贵,因此您通常希望这样做以节省资源(内存和 CPU 周期)。但是,它并非没有成本。当您将数据保存在堆内存中时,您必须free在停止使用它时记住它,否则您的程序会泄漏内存。

于 2012-05-04T17:10:38.417 回答
3

该函数返回who,它是一个struct Person *- 一个指向结构的指针。保存结构的内存由 分配malloc(),函数返回指向该内存的指针。

如果函数被声明为返回struct Person不是指针,那么who也可以被声明为结构。返回时,结构将被复制并返回给调用者。请注意,复制的效率低于简单地返回指向内存的指针。

于 2012-05-04T15:52:32.623 回答
2

默认情况下,结构在 C/C++ 中不是指针(或引用),例如在 Java 中。因此, Struct Person Function() 将返回 struct 本身(按值,制作副本)而不是指针。

您通常不想创建对象的副本(默认情况下为浅副本,或使用复制构造函数创建的副本),因为这很快就会变得非常耗时。

于 2012-05-04T15:52:53.860 回答
1

复制整个结构而不仅仅是指针效率较低,因为指针sizeof通常比sizeof整个结构本身小得多。

此外,结构可能包含指向内存中其他数据的指针,并且盲目复制可能对动态分配的数据造成危险(如果处理一个副本的代码将释放它,则另一个副本将留下无效指针)。

所以浅拷贝几乎总是一个坏主意,除非你确定原始文件超出范围 - 那么你为什么不直接返回一个指向结构的指针(当然是在堆上动态分配的结构,所以它不会像堆栈分配的实体一样被销毁,从函数返回时)。

于 2012-05-04T16:31:01.530 回答