C Programming: A Modern Approach

第16章 结构体、联合体、枚举

2020-03-09  本文已影响0人  橡树人

英文原版:P377

这一章介绍3种新的类型:结构体structures、联合体unions、枚举enumerations
在这3个类型中,结构体是最重要的。

本章主要内容:

16.1节 结构体变量

数组和结构体的比较

数组

结构体

16.1.1 声明结构体变量

假设要记录一个仓库里的零件信息:零件编号(整数类型)、零件名(字符串)、当前数量(整数类型)等,可做如下的结构体声明:

#define NAME_LEN 25
struct {
    int number;
    char name[NAME_LEN+1];
    int on_hand;
} part1, part2;

结构体的成员是按照其声明的顺序依次在内存中存储的

part1结构体变量的存储示意图.png

每个结构体有单独的命名空间,也就是说每个结构体表示一个新的作用域。在每个结构体作用域里声明的任何名字不会跟程序中的其他名字冲突。
比如

#define NAME_LEN 25
struct {
    int number;
    char name[NAME_LEN+1];
    int on_hand;
} part1, part2;
struct {
    char name[NAME_LEN+1];
    int number;
    char sex;
} employee1, employee2;

16.1.2小节 结构体变量的初始化

情形一:在声明的同时使用结构体初始化式进行初始化

#define NAME_LEN 25
struct {
    int number;
    char name[NAME_LEN+1];
    int on_hand;
} part1 = {528, "Disk drive", 10},
  part2 = {914, "Printer cable", 5};

结构体初始化式遵循的规则:

在C99里的指定初始化式

#define NAME_LEN 25
struct {
    int number;
    char name[NAME_LEN+1];
    int on_hand;
} part1 = {.num = 528, .name = "Disk drive", .on_hand = 10},
  part2 = {.num = 914, .name = "Printer cable", .on_hand = 5};

注意:

16.1.3小节 结构体的操作

注意:

//ch16_1.c
#include<stdio.h>
#define NAME_LEN 25

int main()
{
    struct {
      int number;
      char name[NAME_LEN+1];
      int on_hand;
    } part1 = {528, "Disk drive", 10}, part2;
      // part2 = {914, "Printer cable", 5};

    // 访问结构体变量 
    printf("Part1 number: %d\n", part1.number);
    printf("Part1 name: %s\n", part1.name);
    printf("Part1 Quantity on hand: %d\n", part1.on_hand);

    // 对结构体成员的操作,比如赋值、自增、自减等
    part1.number = 258;
    part1.on_hand++;

    printf("Part1 number: %d\n", part1.number);
    printf("Part1 Quantity on hand: %d\n", part1.on_hand);

    // 从键盘上读取一个值给part1.on_hand
    scanf("%d", &part1.on_hand);
    printf("Part1 Quantity on hand: %d\n", part1.on_hand);

    // 整个结构体的赋值操作
    part2 = part1;
    printf("Part2 number: %d\n", part2.number);
    printf("Part2 name: %s\n", part2.name);
    printf("Part2 Quantity on hand: %d\n", part2.on_hand);
    return 0;
}

16.2 结构体类型

16.2.1小节 声明结构体标记

//ch16_2.c

#include<stdio.h>
#define NAME_LEN 25
int main()
{
    // struct {
    //   int number;
    //   char name[NAME_LEN+1];
    //   int on_hand;
    // } part1 = {528, "Disk drive", 10};

    // printf("Part1 number: %d\n", part1.number);
    // printf("Part1 name: %s\n", part1.name);
    // printf("Part1 Quantity on hand: %d\n", part1.on_hand);

    // struct {
    //   int number;
    //   char name[NAME_LEN+1];
    //   int on_hand;
    // } part2;

    //注意,根据C语言规范,part1和part2的类型是不兼容的。


    // part2 = part1;
    // printf("Part2 number: %d\n", part2.number);
    // printf("Part2 name: %s\n", part2.name);
    // printf("Part2 Quantity on hand: %d\n", part2.on_hand);

    struct part {
      int number;
      char name[NAME_LEN+1];
      int on_hand;
    };

    //注意,不能省略struct,part表示一个类型名,只是一个标记名
    // struct part part1, part2;

    //混合使用结构体标记声明和结构体变量声明
    // struct part {
    //   int number;
    //   char name[NAME_LEN+1];
    //   int on_hand;
    // } part1, part2;

    //所有声明为struct part类型的结构体类型是兼容的,可以进行赋值操作
    struct part part1 = {528, "Disk drive", 10};
    struct part part2;
    part2 = part1;
    printf("Part1 number: %d\n", part1.number);
    printf("Part1 name: %s\n", part1.name);
    printf("Part1 Quantity on hand: %d\n", part1.on_hand);
    printf("Part2 number: %d\n", part2.number);
    printf("Part2 name: %s\n", part2.name);
    printf("Part2 Quantity on hand: %d\n", part2.on_hand);

    return 0;
}

16.2.2小节 定义结构体类型

//ch16_2_2.c

#include<stdio.h>
#define NAME_LEN 25

//使用typedef来定义结构体类型
//注意类型的名字Part必须出现在结尾,而不是在struct后面
//由于Part是一个typedef名,则不允许出现struct Part
//所有的Part类型变量都是兼容的
typedef struct {
  int number;
  char name[NAME_LEN+1];
  int on_hand;
} Part;

int main()
{
    // Part part1, part2;
    Part part1 = {528, "Disk drive", 10};
    Part part2;
    part2 = part1;
    printf("Part1 number: %d\n", part1.number);
    printf("Part1 name: %s\n", part1.name);
    printf("Part1 Quantity on hand: %d\n", part1.on_hand);
    printf("Part2 number: %d\n", part2.number);
    printf("Part2 name: %s\n", part2.name);
    printf("Part2 Quantity on hand: %d\n", part2.on_hand);
    return 0;
}

注意

16.2.3小节 结构体作为函数参数和返回值

//ch16_2_3.c

#include<stdio.h>
#include<string.h>
#define NAME_LEN 25

struct part {
  int number;
  char name[NAME_LEN+1];
  int on_hand;
};

void print_part(struct part);

struct part build_part(int number, const char *name, int on_hand);

int main()
{
    struct part part1 = {528, "Disk drive", 10};
    print_part(part1);

    struct part part2 = build_part(120, "Disney", 12);
    print_part(part2);
    return 0;
}

void print_part(struct part p){
    printf("Part number: %d\n", p.number);
    printf("Part name: %s\n", p.name);
    printf("Part Quantity on hand: %d\n", p.on_hand);
}

struct part build_part(int number, const char *name, int on_hand)
{
  struct part p;

  p.number = number;
  strcpy(p.name, name);
  p.on_hand = on_hand;
  return p;
}

性能分析:

16.2.4小节 复合结构体字面量

什么是复合结构体字面量?

(类型) {成员1的值, 成员2的值,...}

复合结构体字面量有哪些用途?

print_part((struct part){528, "Disk drive", 10});

part1 = (struct part){528, "Disk drive", 10};

print_part((struct part){.on_hand = 10, .name = "Disk drive", .number = 528});

16.3节 嵌套使用数组和结构体

结构体嵌套结构体

//ch16_3.c

#include<stdio.h>
#include<string.h>
#define FIRST_NAME_LEN 25
#define LAST_NAME_LEN 25

//结构体标记和结构体类型声明
struct person_name {
    char first[FIRST_NAME_LEN+1];
    char middle_initial;
    char last[LAST_NAME_LEN+1];
};

struct student {
    struct person_name name;
    int id, age;
    char sex;
} student1, student2;

void display_name(struct person_name name);

int main()
{

    strcpy(student1.name.first, "Liyang");
    student1.name.middle_initial = '_';
    strcpy(student1.name.last, "Hao");

    display_name(student1.name);

    struct person_name new_name;
    strcpy(new_name.first, "Leiming");
    new_name.middle_initial = '_';
    strcpy(new_name.last, "Hao");

    student1.name = new_name;
    display_name(student1.name);
    
    return 0;

}

void display_name(struct person_name name){
    printf("Person name first: : %s\n", name.first);
    printf("Person name middle: %c\n", name.middle_initial);
    printf("Person name first: %s\n", name.last);
}

16.3.2小节 结构体数组

//ch16_3_2.c

#include<stdio.h>
#include<string.h>
#define NAME_LEN 25

struct part {
  int number;
  char name[NAME_LEN+1];
  int on_hand;
};

void print_part(struct part);

int main()
{
    //声明结构体数组
    struct part inventory[100];
    int i = 3;

    //访问结构体数组中的某个元素
    print_part(inventory[i]);
    //访问结构体数组中的某个元素的成员
    inventory[i].number = 883;
    //将存储在第i个位置的零件的名字置空
    inventory[i].name[0] = '\0';

    return 0;
}

void print_part(struct part p){
    printf("Part number: %d\n", p.number);
    printf("Part name: %s\n", p.name);
    printf("Part Quantity on hand: %d\n", p.on_hand);
}

16.3.3小节 初始化一个结构体数组

应用场景:

//ch16_3_3.c

//结构体标记
struct dialing_code {
    char *country;
    int code;
};

int main()
{
    const struct dialing_code country_codes[] =
    {
        {"Argetina", 84}, {"Bangladesh", 880},
        {"Brazil", 55}, {"China", 86}
    };
    
    return 0;

}

16.4节 联合体unions

union {
  int i;
  double d;
} u;
结构体变量和联合体变量存储比较示意图.png

读写联合体变量

union {
  int i;
  double d;
} u;

u.i = 82;
u.d = 74.8;

联合类类型的使用场景有哪些?

上一篇 下一篇

猜你喜欢

热点阅读