zhyDaDa的个人站点

目录
枚举
引入
概念
语法
说明
套路
枚举量
枚举只是int
小总结
结构
声明
注意点
初始化
调用
运算
结构指针
结构与函数
结构作为函数的参数和返回值
输入结构
错误示范
结构中的结构
结构数组
指针
自定义类型定义
联合
语法
特点
用法


枚举

引入

为了消除MagicWord, 我们会将一些字面量定义成常量

例如: const char RED="#ff0000";

但是考虑到会有多个同一方面(例如都是颜色)的常量
我们引入枚举这个概念

概念

枚举是一种用户定义的数据类型
使用关键字 enum (全称: enumeration)

语法

声明一个枚举类型
enum 枚举类型名字 {名字0, 名字1, ... 名字n}

这里的”名字”被称为 枚举量

定义一个这种数据类型的变量
enum 枚举类型名字 变量名 = 名字i

可以把这个枚举类型看作和int一样
在其他输入输出方面, 都和int一致

说明

  • 枚举类型名字通常不会真的使用, 重要的是大括号中的名字
  • 大括号中的名字相当于常量的变量名
  • 这些常量的类型必须是int
  • 初始值依次从0n
  • 枚举的实质就是int, ta的意义就是为了方便

套路

由于声明的时候是从0开始赋值的
此时在最后一个名字的后面再加一个名字(一般是numberofxxx)
那么ta的值就是符号的数量
之后在处理循环的时候会很方便

枚举量

声明枚举量的时候可以指定值
没有被指定, 就接着前面的计数
enum COLOR {RED = 3, YELLOW, GREEN=7};
此时YELLOW的值就是4

枚举只是int

如果给枚举类型的变量赋予 不存在/没有意义的值/其他类型 的值
不会报错

小总结

总而言之, 只有当名字在寓意上连贯有意义的情况
也就是比起使用多次const int方便的时候
才会选择使用枚举

结构

要用一个整体表示
一个人的名字, 生日…
时间的年月日…
要使用结构类型

声明

  • 形式1:
struct 结构类型{
    int 结构成员1;
    char 结构成员2;
    double 结构成员3;
};
struct 结构类型 结构变量1, 结构变量2;
  • 形式2:
struct {
    int 结构成员1;
    char 结构成员2;
    double 结构成员3;
}结构变量1, 结构变量2;

无名类型, 以后用不到

  • 形式3:
struct 结构类型{
    int 结构成员1;
    char 结构成员2;
    double 结构成员3;
}结构变量1, 结构变量2;

注意点

  • 声明结构类型也是一条语句, 最后的分号不能漏
  • 在函数的内部声明结构, 出了函数就用不了, 一般在外部声明
  • 声明结构类型声明结构变量 是两个操作, 在上面的形式1就分开了
  • 单独声明结构变量的时候不能漏了操作符 struct

初始化

struct 结构类型 结构变量1 = {7, 'Z', 6.4};
struct 结构类型 结构变量2 = {.成员类型1=7, .成员类型3=6.4};

在第二种初始化的形式, 成员类型2没有赋予初始值, 会自动赋0

调用

int a = 结构变量1.结构成员1;

.也是一个运算符, 用来访问结构成员
结构类型是一种类型, 对ta使用.没有意义

运算

对于整个结构变量, 可以做 赋值/取地址/作为参数传递 这些操作

结构变量1 = (struct point){5, 'b', 9.7};
结构变量2 = 结构变量1;

结构指针

和数组有所区别, 结构变量的名字不是地址
必须使用&运算符取地址

结构与函数

结构作为函数的参数和返回值

type function_name(struct struct_name para)
这个函数的参数是一个 结构变量
+ 整个结构可以作为参数的值传入函数
+ 其实质是, 在函数内新建一个结构变量,
复制调用者的结构的值

函数内发生的不会影响传入的那个结构
因为函数内部的是新的结构
注意区别于数组
+ 可以返回结构

输入结构

没有直接的方式可以一次scanf一个结构
可以自己写一个函数实现

错误示范

struct point
{
    int x;
    int y;
};

void inputStruct(struct point p);
void outputStruct(struct point p);

int main()
{
    struct point p0 = {0, 0};
    inputStruct(p0);
    outputStruct(p0);
    return 0;
}

void inputStruct(struct point p)
{
    scanf("%d", &p.x);
    scanf("%d", &p.y);
    printf("在inputStruct中:\n");
    printf("x: %d\ny: %d\n", p.x, p.y);
}
void outputStruct(struct point p)
{
    printf("在outputStruct中:\n");
    printf("x: %d\ny: %d\n", p.x, p.y);
}

输入: 12 23
输出结果:

12 23
在inputStruct中:
x: 12
y: 23
在outputStruct中:
x: 0
y: 0

这里main函数中定义的p0并未改变
这是因为, 传入的参数是复制过去的p, 已经不是p0

结构中的结构

结构数组

struct point points[] = {{x1,x2}, {1,2}, {0,0}};

举例来说
一个矩形可以用左上角右下角两个来确定
每个, 又是由两个坐标组成的
这时候就产生了嵌套的结构, 此时定义一个矩形的方式如下

struct point
{
    int x;
    int y;
};
struct rectangle{
    struct point pt1;
    struct point pt2;
};
struct rectangle r;

这里的矩形 r 有四个值:
+ r.pt1.x
+ r.pt1.y
+ r.pt2.x
+ r.pt2.y

指针

仍旧以矩形为例, 此时如果再定义一个矩形指针*rp:
struct rectangle r,*rp;
那么有四个形式是等价的:
+ r.pt1.x
+ rp->pt1.x
+ (r.pt1).x
+ (rp->pt1).x

注意, 以下这个形式是错误的:
+ rp->pt1->x

因为pt1是结构, 不是指针

自定义类型定义

在定义完一个结构之后, 每次使用都必须在前面加上struct
这给人以一种 “不是亲生” 的感觉…
typedef就允许你”真正”使用自定义的数据类型

typedef用以声明一个已有数据类型的 别名
typedef int Length;
声明后, 两者用法一致

typedef struct ADate{...} Date;
Date d = {...};

在使用结构时, typedef尤其方便
上面的例子中, ADate可以省略不写, 因为最后实际使用的是Date

联合

联合 (union) 在表面上看起来与 结构(struct)是极为相似的

语法

union Test
{
    int i;
    char c;
} union1, union2;

特点

  • union的每个成员 都占据同一块空间
  • 对其中一个成员赋值, 会覆盖掉其他成员

用法

最常用的场合, 是查看数据在内存中的 储存形式
例如一个联合中有ichar[sizeof(int)]这两个成员
i中写入一个整数后, 可以通过遍历char数组查看每个字节的值
这有助于我们理解数据内部存储的情况
同时, 在做文件处理时, 也可以用这种方式将数据转化为二进制处理

Avatar photo
我是 zhyDaDa

前端/UI/交互/独立游戏/JPOP/电吉他/游戏配乐/网球/纸牌魔术

发表回复