Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从C中的函数返回'struct'_C - Fatal编程技术网

从C中的函数返回'struct'

从C中的函数返回'struct',c,C,今天我在教几个朋友如何使用Cstructs。其中一位问您是否可以从函数返回struct,我回答说:“不!您应该返回指向动态mallocedstructs的指针。” 来自主要从事C++的人,我预期不能通过值返回结构> /Calp>S。在C++中,可以为对象超载运算符=,并使其具有完全意义上的功能,以按值返回对象。然而,在C语言中,您没有这个选项,因此它让我思考编译器实际上在做什么。考虑以下事项: struct MyObj{ double x, y; }; struct MyObj foo

今天我在教几个朋友如何使用C
struct
s。其中一位问您是否可以从函数返回
struct
,我回答说:“不!您应该返回指向动态
malloc
ed
struct
s的指针。”

来自主要从事C++的人,我预期不能通过值返回<代码>结构> /Calp>S。在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;
}    

我理解为什么
structb=a不应工作--不能为数据类型重载
运算符=
。怎么会是
a=foo()编译好吗?它是否意味着除了
struct b=a?可能要问的问题是:
语句与
=
符号一起返回的具体功能是什么?

您可以从函数返回结构(或使用
=
操作符),而不会出现任何问题。它是语言中定义明确的一部分。
struct b=a的唯一问题是没有提供完整的类型<代码>结构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;
}

进行调用时,例如
a=foo()foo()
函数的“隐藏”指针传递。实际上,它可能会变成:

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

foo(&a);
然而,这种方法的具体实现取决于编译器和/或平台。正如Carl Norum所指出的,如果结构足够小,它甚至可以在寄存器中完全传回。

您可以在C中分配结构。
a=b
是有效的语法


您只是在行中省略了部分类型--struct标记--不起作用。

struct b
行不起作用,因为它是一个语法错误。如果您将其展开以包含类型,它将正常工作

struct MyObj b = a;  // Runs fine

C在这里所做的基本上是从源结构到目标结构的
memcpy
。对于
struct
值的赋值和返回(以及C中的其他所有值)

就我所记得的,C的第一个版本只允许返回一个 可以装入处理器寄存器,这意味着您只能返回指向的指针 结构。同样的限制也适用于函数参数

较新的版本允许传递更大的数据对象,如结构。 我认为这一特点在80年代或90年代初已经很普遍


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

是的,我们也可以传递结构和返回结构。您是对的,但实际上没有传递数据类型,该数据类型应该类似于struct 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;
}
#包括
结构标记{
智力数学;
国际物理学;
国际化学;
};
结构分数偏差(结构分数学生1,结构分数学生2);
int main(){
学生成绩结构;
学生:数学=87;
student.chem=67;
学生:物理=96;
结构标记平均值;
平均数学=55;
平均化学=45;
平均物理=34;
//结构标记开发;
结构分数偏差=偏差(学生,平均);
printf(“%d%d%d”,发展数学,发展化学,发展物理);
返回0;
}
结构分数偏差(结构分数学生,结构分数学生2){
结构标记开发;
dev.math=student.mathematics-student2.mathematics;
dev.chem=student.chem-student2.chem;
dev.physics=student.physics-student2.physics;
返回dev;
}

传回结构没有问题。它将按值传递

但是,如果结构包含任何具有局部变量地址的成员,该怎么办

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

因此,我们应该始终避免返回函数的本地内存地址

任何malloced都可以在需要时归还

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一样,名称的内容也会被复制到指定的结构变量。

struct var e2 address作为arg推送到被调用方堆栈,并在那里指定值。事实上,get()在eax reg中返回e2的地址。这类似于引用调用。

struct b=a是一个语法错误。如果您尝试
struct MyObj b=a?@GregHewgill:你完全正确。然而,非常有趣的是,
struct MyObj b=a似乎可以工作:)这完全取决于实现。例如,armcc将在常规参数传递(或返回值)寄存器中传递足够小的结构。这不是返回一个指向局部变量的指针吗?返回结构的内存不能是
foo的一部分
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);
}