今天我在教几个朋友如何使用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 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;
}
下一个示例几乎完全相同,但出于演示目的使用了内置的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;
}
您可以从函数返回结构(或使用=操作符)而不会出现任何问题。这是语言中定义良好的一部分。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;
}
下一个示例几乎完全相同,但出于演示目的使用了内置的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;
}
回传结构体没有问题。它将通过值传递
但是,如果结构体包含任何具有局部变量地址的成员呢
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
因此,我们应该总是尽量避免返回函数的本地内存地址。
任何错误的东西都可以在需要的时候返回