C 语言中的结构体


2021年8月23日, Learn eTutorial
2207

在本教程中,您将学习在 C 语言中构建一个名为 struct 的用户定义数据类型。您将学习如何定义、声明和访问结构体及结构体成员。此外,通过简单易懂的示例,您将掌握嵌套结构体的概念以及在结构体中使用关键字 typedef 的方法。 

在 C 语言中,像 int、float 这样的常用令牌是内置数据类型。但是 C 语言也提供了构建用户自定义数据类型的功能,称为自定义数据类型。结构体是创建这些数据类型的有用工具。

如何在 C 语言中定义结构体?

结构体是由一个或多个数据类型组成的用户定义数据类型,每个结构体都有一个特定的名称。结构体中的数据元素或属性被称为成员。 

数组和结构体之间的基本区别在于,数组的所有元素都必须是相同的数据类型。而结构体可以包含不同的数据类型,这就是为什么结构体总是比数组更受青睐的原因。

语法

声明的原型是


struct struct_name
{
    data_type member_1;
    data_type member_2;
    ...
    ...
    data_type member_n;
};
 

其中,struct 是一个关键字,它通知编译器程序中定义了一个结构体。struct_name 表示结构体的名称,用于声明该特定结构体类型的基本变量。member_1member_2、...、member_n 是相同或不同数据类型的结构体成员。结构体成员必须在大括号 {} 内声明,并以分号(;)结束。最后但同样重要的是,结构体定义必须在右大括号后紧跟一个分号结束。下面是结构体定义的示例:


struct employee  
{  
 int id_no;  
   char name[20];  
   float salary;  
};
 

这里我们定义了一个名为 employee 的结构体,它有三个成员:id_nonamesalary。另外需要注意的重要一点是,定义一个结构体并不会保留任何内存空间,直到它被声明。因此,一个结构体及其成员只有在我们声明一个该结构体类型的变量时才变得活跃。让我们看看如何在 C 语言中创建一个结构体变量。

如何声明结构体变量

要使用结构体,我们需要为它们创建变量,这样内存中就会为该结构体分配一些空间。这可以通过两种方式完成:

  1. 使用结构体定义 

    
    struct struct_name
    {
        data_type member_1;
        data_type member_2;
        ...
        ...
        data_type member_n;
    } var_1, var_2;
    
     
    

    这是示例

    
    struct employee  
    {  
     int id_no;  
       char name[20];  
       float salary;  
    } emp_1,emp_2;  
    
     
    
  2. 在 main() 函数内部使用关键字 struct

    
    struct struct_name var_1,var_2;
     
    

    这是示例

    
    int main()
    {
       struct employee emp_1,emp_2;
    }
    
     
    

在这两种情况下,我们都声明了两个变量 emp_1emp_2

结构体变量的内存分配

现在让我们看一下 C 语言中结构体的内存分配。重要的是要理解,编译器只有在变量声明之后才会在内存中为结构体保留空间。内存保留的顺序遵循结构体成员定义的顺序。因此,在我们的例子中,每个变量(emp_1emp_2)都有 3 个结构体成员(id_nonamesalary)。为了便于理解,内存分配可以可视化如下:
 

Key Features of C

从图中可以明显看出,结构体 employee 的大小是 28 字节的内存。

如何访问结构体成员?

要访问结构体的每个元素,我们必须使用点运算符(.)或成员运算符。其原型是 


var_1.member_1;
var_1.member_2;
 

示例


emp1. id_no;
emp2.name;
 

如何初始化结构体成员

我们可以通过两种不同的方式为结构体变量初始化值。

  1. 使用大括号

    
    struct struct_name
    {
        data_type member_1;
        data_type member_2;
        ...
        ...
        data_type member_n;
    }var_1 = {value for member_1, value for member_2,...},
     var_2 = {value for memeber_1, value for member _2,.};
    
    
     
    

    这是示例

    
    struct employee  
    {  
     int id_no;  
       char name[20];  
       float salary;  
    }emp_1={1001,"Tom",5000};
    
     
    
     
    
  2. 使用点运算符

    
    var_1.member_1 =value;
    var_1.member_2 = value;
     
    

    这是示例

    
    emp_2.id_no = 1002;
    emp_2.salary = 6000.00;
     
    

C 语言结构体示例

下面是一个简单的程序,演示了结构体和结构体成员的定义、声明和初始化。


#include<stdio.h>
#include<string.h>
struct employee
{
    int id_no;
    char name[20];
    float salary;
}emp_1={1001,"Tom",5000};

int main()
{
    struct employee emp_2;

    strcpy(emp_2.name,"Jerry");
    emp_2.id_no = 1002;
    emp_2.salary = 6000.00;

    printf("Employee 1 Details\n");
    printf("Name:%s\n",emp_1.name);
    printf("ID Number:%d\n",emp_1.id_no);
    printf("Salary:%f\n\n",emp_1.salary);

    printf("Employee 2 Details\n");
    printf("Name:%s\n",emp_2.name);
    printf("ID Number:%d\n",emp_2.id_no);
    printf("Salary:%f\n",emp_2.salary);

    return 0;
}

 

输出


Employee 1 Details
Name:Tom
ID Number:1001
Salary:5000.000000

Employee 2 Details
Name:Jerry
ID Number:1002
Salary:6000.000000

在这个例子中,您可以看到使用了 strcpy() 函数来给字符串变量赋值,而不是使用 =。从之前的教程中我们已经知道,在 C 语言中不能对两个字符串变量进行赋值操作。

C 语言中的结构体数组

在上面的程序中,我们只通过创建 2 个结构体变量存储了 2 名员工的详细信息。但如果我们需要存储 50 名员工的数据呢?为 50 名员工创建 50 个变量将会非常繁琐。因此,C 语言提供的最佳解决方案是结构体数组。 

结构体数组可以看作是结构体变量的集合。每个结构体变量存储不同实体的信息。结构体数组的原型如下:
 


struct struct_name var[n];
 

其中 n 是变量的数量。

让我们看看如何使用结构体数组存储 5 名员工的数据


int main()
{
    struct employee emp[5];
    int i;


    printf("Enter Data of 5 employees\n");
    for(i=0; i<5;i++)
    {
      printf("Enter Id_no. :");
      scanf("%d", &emp[i].id_no);
      printf("Enter name :");
      scanf("%s",emp[i].name);
      printf("Enter Salary :");
      scanf("%d", &emp[i].salary);
    }

    printf("Record of 5 Employees\n");
    for(i=0; i<5; i++)
    {

      printf("Id_no : %d\t", emp[i].id_no);
      printf("Name : %s\t", emp[i].name);
      printf("Salary. : %d\n", emp[i].salary);
    }
    return 0;

}
 

在这个程序中,您可以看到我们为 5 名员工创建了一个名为 emp 的数组变量。在处理数组时,我们通常使用 for 循环来输入和输出数据。这个程序的输出将是 5 名员工的数据,包括他们的 id_nonamesalary

结构体中的 typedef

typedef 是 C 语言中一种特殊的关键字。它不能创建新的变量类型,但它能够给用户定义或内置的数据类型赋予一个新的名称。

语法

typedef 的声明语法如下:


typedef data_type new_name;

我们也可以使用结构体来创建新的数据类型。通过使用 typedef,我们可以更改它的名称,之后我们可以将这个新名称用于结构体变量。这里有一个例子来阐明这个过程。


struct universe 
{
        char Earth [5] ;
        char Moon [4] ;
};
typedef struct universe UNV;
UNV u;

 

这里 universe 是一个新的结构体,在声明之后,我们立即使用关键字 typedef 给了它一个新名字 UNV。现在我们可以在需要的地方使用 UNV 这个术语来代替 'universe'。这里我们通过 typedef 在最后一个参数中定义了变量 u。 

上述语句的另一种形式是:
 


typedef struct 
{
        char Earth [5] ;
        char Moon [4] ;
} universe; 
universe u;
 

现在我们将看一个简短的程序,引用 typedef 的用法。


#include <stdio.h>
#include<string.h>
struct universe
{
        char Earth [5] ;
        char Moon [4] ;
};
typedef struct universe UNV;
UNV u;
main()
{
  strcpy(u.Earth,"Blue Planet");
  printf  ("Earth : %s\n", u.Earth) ;
  strcpy(u.Moon,"Fossil Planet");
  printf("Moon : %s\n",u.Moon);
}

输出


Earth : Blue Planet
Moon : Fossil Planet

C 语言中的嵌套结构体

C 语言为结构体提供的另一个特性是嵌套结构体。一个结构体内部包含另一个结构体被称为嵌套结构体。嵌套结构体通过在另一个结构体内部声明一个结构体,就像我们在一个结构体内部声明其他成员一样,从而有助于创建复杂的数据类型。 

嵌套可以通过两种方式完成

  1. 使用独立的结构体

    
    struct structure1
                  {
                         - - - - - - - - - -
                         - - - - - - - - - -
                  };
    
                  struct structure2
                  {
                         - - - - - - - - - -
                         - - - - - - - - - -
                         struct structure1 var;
                  };
    
     
    
  2. 使用嵌入式结构体

    
    struct structure2
                  {
                         - - - - - - - - - -
                         - - - - - - - - - -
    
                  struct structure1
                  {
                         - - - - - - - - - -
                         - - - - - - - - - -
                        
                  }var_structure1;
    }var_structure2;
    
     
    

如何访问嵌套结构体成员

我们可以通过使用一连串的点运算符轻松访问嵌套结构体成员。


var_structure2.var_structure1.member;
 

例如,我们可能需要在一个结构体中存储员工实体的出生日期。由于这个属性包含日期、月份和年份等子部分,我们需要将其定义为另一个结构体,并将其嵌套到员工结构体中。

使用独立结构体的嵌套结构体示例


#include<string.h>
struct DOB
{
    int dd;
    int mm;
    int yy;
};
struct employee
{
    int id_no;
    char name[20];
    struct DOB dob;
};

int main()
{
    struct employee emp;

    emp.id_no=1001;
    strcpy(emp.name,"TOM");
    emp.dob.dd = 17;
    emp.dob.mm = 02;
    emp.dob.yy = 2000;

    printf("Employee Details\n\n");
    printf("Name:%s\n",emp.name);
    printf("ID Number:%d\n",emp.id_no);
    printf("DOB(dd:mm:yyyy):%d-%d-%d\n\n",emp.dob.dd,emp.dob.mm,emp.dob.yy);


    return 0;
}

 

输出


Employee Details

Name:TOM
ID Number:1001
DOB(dd:mm:yyyy):17-2-2000

该程序解释了如何嵌套两个独立的结构体。本程序中定义的两个结构体是 DOB 和 employee。DOB 在 employee 内部声明,并通过一连串的点运算符进行访问。

通过嵌入结构体实现嵌套结构体的示例

同样的功能可以通过使用嵌入式结构体来实现,即在 employee 结构体内部定义和声明 DOB 结构体,如下所示。这种嵌套方式的主要优点是减少了代码量,但当嵌套深度超过两层时,它就不适用了。


#include<stdio.h>
#include<string.h>

struct employee
{
    int id_no;
    char name[20];
    struct DOB
{
    int dd;
    int mm;
    int yy;
}dob;
};

int main()
{
    struct employee emp;

    emp.id_no=1001;
    strcpy(emp.name,"TOM");
    emp.dob.dd = 17;
    emp.dob.mm = 02;
    emp.dob.yy = 2000;

    printf("Employee Details\n\n");
    printf("Name:%s\n",emp.name);
    printf("ID Number:%d\n",emp.id_no);
    printf("DOB(dd:mm:yyyy):%d-%d-%d\n\n",emp.dob.dd,emp.dob.mm,emp.dob.yy);


    return 0;
}

 

注意:结构体的嵌套可以进行到任何程度。