从C中的函数返回一个`struct`

今天,我正在教几个朋友如何使用C struct 。 其中一个人问你是否可以从一个函数返回一个struct ,我回答说:“不!你会返回指向dynamicmalloc struct的指针。”

来自主要从事C ++的人,我期望不能通过值返回struct 。 在C ++中,你可以为你的对象重载operator = ,并且有一个函数根据值返回你的对象。 但是,在C中,你没有这个选项,所以它让我思考编译器实际上在做什么。 考虑以下:

 struct MyObj{ double x, y; }; struct MyObj foo(){ struct MyObj a; ax = 10; ay = 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 =你的数据types。 这是怎么a = foo(); 编译好吗? 这是否意味着除了struct b = a; ? 也许要问的问题是:与= sign相关的return语句到底是做什么的?

[编辑]好吧,我只是指出struct b = a是一个语法错误 – 这是正确的,我是一个白痴! 但是这使得它更加复杂! 使用struct MyObj b = a确实可行! 我在这里错过了什么?

你可以返回一个函数的结构(或使用=运算符),没有任何问题。 这是语言的一个明确的部分。 struct b = a唯一的问题是你没有提供完整的types。 struct MyObj b = a将工作得很好。 您也可以将结构传递函数 – 对于parameter passing,返回值和赋值,结构与任何内置types完全相同。

下面是一个简单的演示程序,它将所有三个结构作为parameter passing,从函数返回一个结构体,并在赋值语句中使用结构体:

 #include <stdio.h> struct a { int i; }; struct af(struct ax) { struct ar = x; return r; } int main(void) { struct ax = { 12 }; struct ay = f(x); printf("%d\n", yi); return 0; } 

下一个例子几乎完全一样,但为了演示的目的使用内置的inttypes。 这两个程序在parameter passing,赋值等方面具有相同的行为。

 #include <stdio.h> int f(int x) { int r = x; return r; } int main(void) { int x = 12; int y = f(x); printf("%d\n", y); return 0; } 

当进行诸如a = foo();的调用时a = foo(); ,编译器可能会将结果结构的地址推入堆栈,并将其作为“隐藏”指针传递给foo()函数。 实际上,它可能会变成这样:

 void foo(MyObj *r) { struct MyObj a; // ... *r = a; } foo(&a); 

但是,这个的确切实现取决于编译器和/或平台。 正如卡尔·诺鲁姆(Carl Norum)指出的那样,如果结构足够小,甚至可以完全归还到registry中。

struct b行不起作用,因为它是一个语法错误。 如果你扩大它包括types,它会工作得很好

 struct MyObj b = a; // Runs fine 

C在这里做的实质上是从源结构到目标的memcpy 。 对于struct值的赋值和返回都是如此(实际上C中的每个其他值)

是的,我们可以通过结构和返回结构。 你是对的,但你实际上没有传递数据types应该是这样的结构MyObj b = a。

其实我也来了解,当我试图find一个更好的解决scheme,返回多个值的函数, 而不使用指针或全局variables。

下面是同样的例子,它计算出一个学生的平均偏差。

 #include<stdio.h> struct marks{ int maths; int physics; int chem; }; struct marks deviation(struct marks student1 , struct marks student2 ); int main(){ struct marks student; student.maths= 87; student.chem = 67; student.physics=96; struct marks avg; avg.maths= 55; avg.chem = 45; avg.physics=34; //struct marks dev; struct marks dev= deviation(student, avg ); printf("%d %d %d" ,dev.maths,dev.chem,dev.physics); return 0; } struct marks deviation(struct marks student , struct marks student2 ){ struct marks dev; dev.maths = student.maths-student2.maths; dev.chem = student.chem-student2.chem; dev.physics = student.physics-student2.physics; return dev; } 

可以在C中指定结构体a = b; 是有效的语法。

您只需在行中留下部分types的结构标记,即不起作用。

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

更新的版本允许像结构一样传递更大的数据对象。 我觉得这个function在八十年代或九十年代初已经很普遍了。

但是,数组仍然可以作为指针传递和返回。

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

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

 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()返回,名字的本地地址将被释放。 所以,如果我们尝试访问该地址,则在调用者中,可能会导致分段错误,因为我们正在尝试释放地址。 那很不好..

因为e1.id将完全有效,因为它的值将被复制到e2.id

所以,我们应该总是尽量避免返回一个函数的本地内存地址。

任何mableced可以返回,当时想要的

 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一样,名字的内容被复制到指定的结构variables中。