C 语言中结构体作为函数参数


2021年8月23日, Learn eTutorial
3006

在本教程中,您将掌握通过按值传递和按引用传递这两种方法将结构体作为函数参数。此外,您还将学习如何通过简单易懂的示例将结构体返回给函数。 

我们假设您在开始本教程之前已经具备C语言中结构体和函数的知识。如果不是,您可以参考我们的C语言函数C语言结构体教程,以便更好地理解此主题。

我们可以像使用普通变量一样使用结构体作为函数参数。结构体支持按值传递和按引用传递两种方式。因此,C语言基本上提供了3种不同的方式来将结构体传递给函数。

  • 第一种方法是将结构体成员传递给函数。 
  • 第二种方法是将整个结构体传递给函数(按值传递)。
  • 第三种方法是将结构体作为指针传递(按引用传递)。

如何将结构体成员作为函数参数传递

让我们开始尝试理解下面这个简单的程序。 


// How to pass structure members to a function
#include<stdio.h>
struct employee
{
    char name[20];
    int id_no;
    int salary;
};
// function declaration
void display_structure(char name[], int id_no, int salary);

int main()
{
    struct employee emp = {"Tom", 1001, 70000};
    display_structure(emp.name, emp.id_no, emp.salary);// function call

    return 0;
}
// function definition
void display_structure(char name[], int id_no, int salary)
{
    printf("Name of Employee: %s\n", name);
    printf("Id No of Employee: %d\n", id_no);
    printf("Salary of Employee: %d\n", salary);
    printf("\n");
}

 

在上面的代码片段中,我们创建了一个名为employee的结构体,它有3个成员:nameid_nosalary。由于结构体总是声明在main函数之外,所以结构体具有全局作用域,这意味着结构体的生命周期贯穿整个程序。

紧随结构体声明之后,我们给出了函数声明,它向编译器提供信息,告知程序中存在该函数。在此,函数声明的返回类型为void,因此不返回任何值。函数名为display_strucute,它实际上会打印作为参数传递的结构体成员的值。

在main函数内部,声明并初始化了结构体变量emp,从而在内存中分配了一些空间。然后调用函数,传递实际参数。现在,形式参数接收实际参数的值。 
最后,我们定义了打印结构体的函数。输出将是


Name of Employee: Tom
Id No of Employee: 1001
Salary of Employee: 70000

这种将结构体成员传递给函数的方式的缺点是,它只适用于结构体成员数量有限的情况。

如何通过值将结构体传递给函数

C语言支持的另一种方法是通过将结构体变量作为参数来传递整个结构体。这种方法也称为按值传递,因为对结构体成员变量所做的任何更改都不会反映在原始结构体中。

您可以检查下面的示例来证明这一点。


// Passing entire structure to function as call by value
#include<stdio.h>
#include<string.h>

struct employee
{
    char name[10];
    int salary;
};

void update(struct employee E)// formal argument
{
    E.salary = 80000;
    printf("Salary of %s updated to %d\n",E.name,E.salary);
}

int main()
{
    struct employee emp;
    strcpy(emp.name,"Tom");
    emp.salary = 70000;
    printf("Salary of %s in main function is given as %d\n",emp.name,emp.salary);

    update(emp);//actual argument
    printf("Salary of %s after function call is %d\n",emp.name,emp.salary);

    return 0;
}

 

让我们仔细研究一下程序,以清楚地理解按值传递的概念。我们都知道所有程序都从main()函数开始,所以首先我们使用以下语句创建了一个结构体变量emp


struct employee emp;
 

每当创建一个结构体变量时,根据结构体成员的大小,都会在内存中分配一些空间。在我们的例子中,emp将在内存中分配14个字节。emp的内存分配如下:

Structures as function arguments

使用printf函数,显示结构体成员的值。

在下一行,我们按如下方式调用了用户定义的函数:


update(emp);
 

在这里,我们在函数调用时传递整个结构体emp(实际参数)到函数定义。现在控制转移到函数定义update(),其中形式参数E接收实际参数的值,即整个结构体本身。下面显示了内存分配。

Structures as function arguments

比较两张图片,您可以看到它们内存位置上的区别。这证明了两个结构体位于不同的位置,并且彼此完全独立。


E.salary = 80000;
 

因此,在update()函数中,E. salary被赋值为新的工资80000,并在该函数内打印。当函数结束时,控制会返回到main函数,在那里我们再次打印工资的值,输出结果为70000

由此,我们可以得出结论,在按值传递方法中,对形式参数所做的任何更改都不会反映在实际参数上。 

上述程序的输出将如下所示:


Salary of Tom in main function is given as 70000
Salary of Tom updated to 80000
Salary of Tom after function call is 70000

现在,让我们讨论一下在将结构体传递给函数时按值传递方法的一些限制。

  1. 如果结构体的大小很大,结构体的复制可能会花费一些时间,从而影响程序的效率。
  2. 将结构体复制到形式参数会消耗额外的内存空间。
     

如何通过引用将结构体传递给函数

为了克服按值传递的局限性,C语言利用指针来传递结构体。为了实现按引用传递的方法,我们对上述程序进行了少量修改,如下所示:


// Passing entire structure to function as call by reference
#include<stdio.h>
#include<string.h>
struct employee
{
    char name[20];
    int salary;
};

void update(struct employee *E)//E points the location of structure
{
    E->salary = 80000;
    printf("Salary of %s updated to %d\n",E->name,E->salary);
}

int main()
{
    struct employee emp;
    strcpy(emp.name,"Tom");
    emp.salary = 70000;
    printf("Salary of %s in main function is given as %d\n",emp.name,emp.salary);

    update(&emp);// passing the address of structure emp
    printf("Salary of %s after function call is %d\n",emp.name,emp.salary);

    return 0;
}

 

在此代码片段中,在函数调用时,我们没有传递结构体本身,而是传递了结构体emp的地址。形式参数E将接收地址并指向结构体emp本身的内存位置。

现在,结构体Eemp位于同一位置,因此对形式参数所做的任何更改都将无缝地反映在实际参数上。

以下图示阐明了这一概念:

Structures as function arguments

我们对程序所做的另一个更改是,我们没有使用点运算符(.)来访问成员变量,而是使用了箭头运算符(->)来获取结构体变量所持有的值。

程序的输出将是:


Salary of Tom in main function is given as 70000
Salary of Tom updated to 80000
Salary of Tom after function call is 80000

与按值传递不同,在这里,在update()函数中修改的工资也会在main函数中反映出来,这是因为值修改实际上发生在原始结构体本身。

如何将结构体数组作为函数参数传递

就像传递整数数组一样,将结构体数组传递给函数也是可能的。 
下面的示例说明了将结构体数组传递给函数的方法。 


#include<stdio.h>
#include<string.h>
struct employee
{
    char name[20];
    int id_no;
    int salary;
};



int main()
{
    struct employee emp[3]={
        {"TOM",10001,70000},
        {"JERRY",10002,75000},
        {"GILL",10003,80000},
        };
    display_structure(emp); //function call

    return 0;
}
// function definition
void display_structure(struct employee E[])
{
    for(int i=0;i<3;i++){
     printf("Employee %d\n",(i+1));
    printf("Name: %s\n",E[i].name);
    printf("Id_no: %d\n",E[i].id_no);
    printf("Salary:  %d\n",E[i].salary);
     printf("\n");
    }

}
 

输出


Employee 1
Name: TOM
Id_no: 10001
Salary:  70000

Employee 2
Name: JERRY
Id_no: 10002
Salary:  75000

Employee 3
Name: GILL
Id_no: 10003
Salary:  80000

将结构体数组传递给函数并非难事。我们需要在函数中使用正确的数组原型,并使用for循环遍历数组中的每个元素。 

如何将结构体返回到函数

到目前为止,我们已经了解了如何将结构体传递给函数,现在是时候学习将结构体返回给函数了。

这里提供了一个计算两个复数之和的示例。我们知道复数包含实部和虚部。两个复数相加意味着两个实部相加,两个虚部相加,如下面的程序所示。 


#include<stdio.h>
#include<conio.h>

struct complex
{
    float real;
    float imag;
};

struct complex add(struct complex, struct complex);
int main()
{

  struct complex c1,c2,c3;
  printf("Enter the first complex number:");
  scanf("%f%f",&c1.real,&c1.imag);
  printf("Enter the second complex number:");
  scanf("%f%f",&c2.real,&c2.imag);
  c3= add(c1,c2);
  if (c3.imag<0)
   printf("The sum of two complex numbers is %.1f - %.1fi",c3.real,-c3.imag);
  else
    printf("The sum of two complex numbers is %.1f + %.1fi",c3.real,c3.imag);
  return 0;
}

struct complex add(struct complex x,struct complex y)
{
    struct complex z;
    z.real=x.real+y.real;
    z.imag=x.imag+y.imag;
    return z;
};

 

在上面的代码片段中,结构体名为complex,有两个float数据类型的成员real和image。


struct complex add(struct complex, struct complex);
 

这条语句是函数声明,函数名为add,它返回一个结构体数据类型,并且还传递两个结构体。

在main函数中,我们使用结构体变量c1c2输入了两个复数。在c3中存储了从函数add返回的值。

add函数将两个复数作为参数xy,并将x和y的实部相加的值存储在z中,虚部也同样处理。最后,函数返回相加的值,即z。根据c3中的值,输出显示如下:


Enter the first complex number:2.1
3.2
Enter the second complex number:4.5
5.6
The sum of two complex numbers is 6.6 + 8.8i
----------------------------------------------------------------------------------

Enter the first complex number:2
3
Enter the second complex number:-5
-5
The sum of two complex numbers is -3.0 - 2.0i