第十六章、结构体

结构体(Structure)是用于将不同的类型的数据通过结构体声明在逻辑上组合成一个整体的复合数据类型。它将一系列不同数据类型的数据放在一起,将其看成一个整体。这样更有利于逻辑分类。

结构体的作用 是封装相关联的数据成为一个整体,有利于数据管理。提高编程的效率。

使用结构体的函数是使代码模块化,增强可读性和易用性。

1. 结构体类型

在使用结构体之前我们要先使用结构体声明,将一系列数据类型整合成一个结构体类型,然后再使用这个新创建的结构体类型来声明变量和保存数据。

结构体类型声明的语法

struct [结构体名] {
    数据类型1  成员变量名1, 成员变量名2, 成员变量名3, ...;
    数据类型2  成员变量名4;
    // ... 结构体内其它成员变量
}[变量名1[={初始化列表1}]][,变量名2[={初始化列表2}], ...];

说明:

示例:

声明一个学生(student)类型的结构体,用于存放每一个学生的姓名(name),年龄(age)和身高(height)信息。

struct student {
   char name[32];  // 姓名
   int age;  // 年龄
   float height; // 身高
};

以上我们声明了一个新的类型 struct student,这个类型的变量的内部有三个成员,分别是name占 32 个字节,age 占 4 个字节,height 占 4 个字节。也就是说每一个 struct student 类型的变量至少占用 40 字节(32+4+4)。这里说至少占 40 个字节,那就是说还有可能会多于 40 个字节,这是因为结构体对齐问题引起的。我们后面会讲。

使用结构体类型声明变量的语法和使用内建数据类型声明变量的语法相同,但需要在结构体类型名前加入关键字 struct

使用结构体声明变量的语法:

1、在声明结构体时直接声明结构体变量。

struct [结构体名] {
    // ... 结构体内成员变量
} 变量名[ = {成员变量1初始值, 成员变量1初始值, ... }];

2、先声明结构体,然后再使用结构体类型创建结构体变量。

// 语法1:按成员声明顺序初始化成员变量
struct 结构体名 变量名 = {成员变量1初始值, 成员变量1初始值, ... };

// 语法2:按成员变量名初始化成员变量
struct 结构体名 变量名 = {.成员变量1 = 初始值1, .成员变量2 = 初始值2, ... };

说明:

  1. 语法中的中括号([])代表其中的内容可以省略。
  2. 结构体名前面必须添加关键字 struct
  3. 等号和后面的初始化列表可以省略不写,如果不写入初始化列表,该结构体各个成员变量的值可能是任意值。
  4. 如果声明结构体变量时给出的初始化列表,则没有指定初始值的成员变量的初始值为零值

我们使用 struct student 类型声明变量,用于保存学生张三、李四、王五和100个学生信息的数组 class1。

参考代码如下:

struct student {
   char name[32];  // 姓名
   int age;  // 年龄
   float height; // 身高
} zhang3 = {"zhang san", 18, 1.73};

// 初始化列表的顺序必须和结构体成员变量名声明顺序相同。
struct student li4 = {"li si", 19, 1.80};

// 成员变量初始化顺序可以按成员变量名给出。
struct student wang5 = {.age = 16, .height = 1.71, .name = "wang wu"};

// 定义100个学生类型的数组 class1;
struct student class1[100];

成员访问运算符

我们定义的结构体类型的变量,那我们要如何访问结构体变量内部的数据呢?接下来我们学习 C 语言中专门用来访问结构体(或联合体,后面会讲)成员的成员访问运算符.)。

成员访问运算符.)的作用是引用结构体(或联合体)内部的成员变量。

语法:

结构体变量.成员变量

使用 . 运算符我们就可以访问(取值)或修改(赋值)结构体成员的变量了。

综合示例如下:

// filename: struct_declaration.c
#include <stdio.h>

struct student {
    char name[32];  // 姓名
    int age;  // 年龄
    float height; // 身高
} zhang3 = {"zhang san", 18, 1.73};

int main(int argc, char * argv[]) {
    // 初始化列表的顺序必须和结构体成员变量名声明顺序相同。
    struct student li4 = {"li si", 19, 1.80};

    // 成员变量初始化顺序可以按成员变量名给出。
    struct student wang5 = {.age = 16, .height = 1.71, .name = "wang wu"};

    printf("姓名:%s,年龄:%d,身高:%.2f\n", zhang3.name, zhang3.age, zhang3.height);
    printf("姓名:%s,年龄:%d,身高:%.2f\n", li4.name, li4.age, li4.height);
    printf("姓名:%s,年龄:%d,身高:%.2f\n", wang5.name, wang5.age, wang5.height);

    // 打印结构体变量占用的内存空间的大小。
    printf("sizeof(zhang3): %ld\n", sizeof(zhang3));
    printf("sizeof(struct student): %ld\n", sizeof(struct student));

    return 0;
}

运行结果如下:

weimingze@mzstudio:~$ gcc -o struct_declaration struct_declaration.c
weimingze@mzstudio:~$ ./struct_declaration
姓名:zhang san,年龄:18,身高:1.73
姓名:li si,年龄:19,身高:1.80
姓名:wang wu,年龄:16,身高:1.71
sizeof(zhang3): 40
sizeof(struct student): 40

练习:

循环输入几个学生的姓名,年龄和身高,当输入年龄输入负数时结束输入,打印你输入的所有学生的姓名,年龄和身高。