今天我教了几个朋友如何使用C struct
s.其中一个问你是否可以struct
从一个函数返回一个函数,我回答说:"不!你会返回指向动态malloc
编辑struct
的指针."
来自主要使用C++的人,我期望无法struct
按值返回s.在C++中,您可以operator =
为对象重载并完全理解为具有按值返回对象的函数.但是,在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;
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么struct b = a;
不能工作 - 你不能operator =
为你的数据类型重载.它是如何a = foo();
编译罚款?这是否意味着什么struct b = a;
?也许要问的问题是:return
与=
签名相关的陈述到底是做什么的?
[编辑]:好的,我只是指出struct b = a
是一个语法错误 - 这是正确的,我是一个白痴!但这使它变得更加复杂!使用struct MyObj b = a
确实有效!我在这里错过了什么?
Car*_*rum 182
您可以从函数返回结构(或使用=
运算符)而不会出现任何问题.它是语言中定义明确的部分.唯一的问题struct b = a
是你没有提供完整的类型. struct MyObj b = a
会工作得很好.您也可以将结构传递给函数 - 为了参数传递,返回值和赋值,结构与任何内置类型完全相同.
这是一个简单的演示程序,它完成所有三个 - 将结构作为参数传递,从函数返回结构,并在赋值语句中使用结构:
#include <stdio.h>
struct a {
int i;
};
struct a f(struct a x)
{
struct a r = x;
return r;
}
int main(void)
{
struct a x = { 12 };
struct a y = f(x);
printf("%d\n", y.i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
下一个示例几乎完全相同,但使用内置int
类型进行演示.这两个程序在参数传递,赋值等的传值方面具有相同的行为:
#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;
}
Run Code Online (Sandbox Code Playgroud)
Gre*_*ill 31
在进行调用时a = foo();
,编译器可能会将结果结构的地址压入堆栈并将其作为"隐藏"指针传递给foo()
函数.实际上,它可能会变成:
void foo(MyObj *r) {
struct MyObj a;
// ...
*r = a;
}
foo(&a);
Run Code Online (Sandbox Code Playgroud)
但是,具体实现取决于编译器和/或平台.正如Carl Norum指出的那样,如果结构足够小,它甚至可以完全传回寄存器.
Jar*_*Par 13
该struct b
行无效,因为它是语法错误.如果你将它扩展为包含类型它将工作得很好
struct MyObj b = a; // Runs fine
Run Code Online (Sandbox Code Playgroud)
C在这里做的事实上是memcpy
从源结构到目标.对于赋值和返回struct
值(以及C中的所有其他值)都是如此
是的,我们可以传递结构和返回结构.你是对的,但你实际上没有传递数据类型,这应该像这个结构MyObj b = a.
实际上我也开始知道我什么时候试图找到一个更好的解决方案,在不使用指针或全局变量的情况下返回多个函数值.
现在下面是相同的例子,它计算学生标记与平均值的偏差.
#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;
}
Run Code Online (Sandbox Code Playgroud)
小智 6
传回结构没有问题。它将按值传递
但是,如果结构包含任何具有局部变量地址的成员呢?
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);
}
Run Code Online (Sandbox Code Playgroud)
现在,这里e1.name
包含函数的本地内存地址get()
。一旦get()
返回,name 的本地地址就会被释放。因此,在调用者中,如果我们尝试访问该地址,则可能会导致分段错误,因为我们正在尝试释放地址。那很不好..
当作为e1.id
会完全有效,它的价值将被复制到e2.id
所以,我们应该总是尽量避免返回函数的本地内存地址。
任何 malloced 都可以在需要时返回
据我所记得,C的第一个版本只允许返回一个适合处理器寄存器的值,这意味着您只能返回一个指向结构的指针。相同的限制适用于函数参数。
最新版本允许传递较大的数据对象(如结构)。我认为此功能在80年代或90年代初已经很普遍。
但是,数组仍然只能作为指针传递和返回。