目录
1 什么是枚举
2 定义枚举类型
2.1 语法格式
2.2 枚举元素的特点
2.3 案例演示
3 枚举变量
3.1 什么是枚举变量
3.2 定义枚举变量的多种方式
3.3 案例演示 1:标准版枚举类型
3.4 案例演示 2:简化版枚举类型
3.5 案例演示 3:匿名枚举类型
4 枚举的遍历
4.1 连续枚举常量的遍历
4.2 非连续枚举常量的遍历
4.2.1 手动遍历每个枚举常量
4.2.2 使用数组存储枚举常量
5 枚举在 switch 中使用
6 枚举数组
1 什么是枚举
枚举(Enumeration)是 C 语言中的一种用户自定义数据类型,用于定义一组相关的常量。它允许为这些常量赋予有意义的名称,从而增强代码的可读性和可维护性。
如果我们要定义一个变量来表示一周中的某一天,可以使用枚举类型来确保该变量的值仅限于七个预定义的有效值之中。这样能够有效地限制变量的取值范围,确保其准确性与合理性。
2 定义枚举类型
2.1 语法格式
枚举类型使用 enum 关键字定义,通过为一组相关常量命名来创建一种新的数据类型。枚举名称(通常使用全大写表示)和其中的元素名称均为标识符(需要满足标识符的命名规则)。定义一个枚举就是定义了一种新的数据类型,其基本语法如下:
// 不指定值的枚举
enum 枚举名称 {枚举元素1,枚举元素2,...枚举元素N
}; // 分号不要忘记// 指定部分值的枚举
enum 枚举名称 {枚举元素1 = 值1,枚举元素2,...枚举元素N
}; // 分号不要忘记// 完全指定值的枚举
enum 枚举名称 {枚举元素1 = 值1,枚举元素2 = 值2,...枚举元素N = 值N
}; // 分号不要忘记
枚举类型可以在 main 函数外面定义,也可以在 main 函数里面定义。
- 将枚举类型定义在 main 函数外面(通常是文件的全局作用域),可以使枚举类型在整个文件中可见,便于在多个函数中使用。
- 将枚举类型定义在 main 函数内部,可以使枚举类型的作用域限制在 main 函数内,避免污染全局命名空间。
2.2 枚举元素的特点
枚举元素,也称为枚举成员或枚举常量,具有以下特征:
唯一性:在同一枚举类型中,每个枚举常量的值必须唯一,即不能有两个或多个枚举常量具有相同的值。
整数类型:枚举常量的值必须是整数类型,虽然在大多数编程语言中枚举常量本身不直接表现为整数,但在底层它们通常由整数(通常是 int 类型)表示。
自定义值:定义枚举时,可以为枚举元素指定自定义的整数值,但需确保这些值的唯一性和整数类型。
自动递增赋值:
- 如果没有为枚举常量显式指定值,编译器会自动为它们分配值。这些值通常从 0 开始,依次递增。例如,在一个包含三个枚举常量的枚举类型中,第一个枚举常量会被分配值 0,第二个为 1,第三个为 2。
- 如果为第一个枚举常量显式赋值,后续的枚举常量没有显式赋值,则后续枚举常量会从该值开始依次递增。例如,如果给第一个枚举常量显式赋值为 1,则第二个枚举常量的值默认为 2,第三个默认为 3,依此类推。
- 如果中间的某个枚举常量显式赋了某个值,而下一个常量没有显式赋值,那么其默认值将从上一个枚举常量的值开始依次递增。例如,如果给第一个枚举常量显式赋值为 1,则第二个枚举常量的值默认为 2,再给第三个枚举常量显式赋值为 10,则第四个枚举常量的值默认为 11,依此类推。
2.3 案例演示
#include <stdio.h>// 定义枚举类型,表示星期一到星期天,枚举元素的值自动分配,从 0 到 6
enum WEEKDAY
{MONDAY, // 默认值为 0TUESDAY, // 默认值为 1WEDNESDAY, // 默认值为 2THURSDAY, // 默认值为 3FRIDAY, // 默认值为 4SATURDAY, // 默认值为 5SUNDAY // 默认值为 6
};// 定义枚举类型,表示一月到十二月,为第一个枚举元素 JANUARY 指定值 1,其余元素依次递增
enum MONTH
{JANUARY = 1, // 显式赋值为 1FEBRUARY, // 默认值为 2MARCH, // 默认值为 3APRIL, // 默认值为 4MAY, // 默认值为 5JUNE, // 默认值为 6JULY, // 默认值为 7AUGUST, // 默认值为 8SEPTEMBER, // 默认值为 9OCTOBER, // 默认值为 10NOVEMBER, // 默认值为 11DECEMBER // 默认值为 12
};// 定义枚举类型,表示北京地区一年四季的平均温度,为每个枚举元素指定特定值,需确保这些值的唯一性和整数类型
enum SEASON
{SPRING = 18, // 显式赋值为 18SUMMER = 30, // 显式赋值为 30AUTUMN = 20, // 显式赋值为 20WINTER = -5 // 显式赋值为 -5
};// 定义枚举类型,测试自动递增赋值
enum EXAMPLE
{NUMA = 10, // 显式赋值为 10NUMB, // 默认值为 11NUMC = 20, // 显式赋值为 20NUMD // 默认值为 21
};int main()
{return 0;
}
3 枚举变量
3.1 什么是枚举变量
定义变量时,如果指定其类型为我们所定义的枚举类型,该变量就称为枚举变量。
枚举变量的值必须是该枚举类型中的一个枚举常量,不能是其他值。如果是其他值,就失去了枚举的意义,不建议这么做。
3.2 定义枚举变量的多种方式
第一种:先定义枚举类型,再定义枚举变量。
// 定义枚举类型
enum DAY {MON = 1,TUE,WED,THU,FRI,SAT,SUN
};// 使用枚举类型定义枚举变量
enum DAY day; // day 是变量名
第二种:定义枚举类型的同时声明枚举变量。
enum DAY {MON = 1,TUE,WED,THU,FRI,SAT,SUN
} day; // 直接跟上一个变量名称enum DAY {MON = 1,TUE,WED,THU,FRI,SAT,SUN
} day = TUE; // 可以在这里直接进行赋值enum DAY {MON = 1,TUE,WED,THU,FRI,SAT,SUN
} day1,day2; // 可以一次性声明多个变量
第三种:定义枚举类型的同时声明枚举变量,且省略枚举名称。
enum // 省略枚举名称
{ MON = 1,TUE,WED,THU,FRI,SAT,SUN
} day = TUE; // 可以在这里直接进行赋值enum // 省略枚举名称
{ MON = 1,TUE,WED,THU,FRI,SAT,SUN
} day1,day2; // 可以一次性声明多个变量
3.3 案例演示 1:标准版枚举类型
#include <stdio.h>// 定义枚举类型,表示星期一到星期天,枚举元素的值自动分配,从 0 到 6
enum WEEKDAY
{MONDAY, // 默认值为 0TUESDAY, // 默认值为 1WEDNESDAY, // 默认值为 2THURSDAY, // 默认值为 3FRIDAY, // 默认值为 4SATURDAY, // 默认值为 5SUNDAY // 默认值为 6
};// 定义枚举类型,表示一月到十二月,为第一个枚举元素 JANUARY 指定值 1,其余元素依次递增
enum MONTH
{JANUARY = 1, // 显式赋值为 1FEBRUARY, // 默认值为 2MARCH, // 默认值为 3APRIL, // 默认值为 4MAY, // 默认值为 5JUNE, // 默认值为 6JULY, // 默认值为 7AUGUST, // 默认值为 8SEPTEMBER, // 默认值为 9OCTOBER, // 默认值为 10NOVEMBER, // 默认值为 11DECEMBER // 默认值为 12
};// 定义枚举类型,表示北京地区一年四季的平均温度,为每个枚举元素指定特定值,需确保这些值的唯一性和整数类型
enum SEASON
{SPRING = 18, // 显式赋值为 18SUMMER = 30, // 显式赋值为 30AUTUMN = 20, // 显式赋值为 20WINTER = -5 // 显式赋值为 -5
};// 定义枚举类型,测试自动递增赋值
enum EXAMPLE
{NUMA = 10, // 显式赋值为 10NUMB, // 默认值为 11NUMC = 20, // 显式赋值为 20NUMD // 默认值为 21
};int main()
{// 定义枚举变量并赋值// 枚举变量的值必须是该枚举类型中的一个枚举常量,不能是其他值enum WEEKDAY today = WEDNESDAY;enum MONTH currentMonth = OCTOBER;enum SEASON currentSeason = AUTUMN;enum EXAMPLE num = NUMD;// 输出枚举变量的值printf("今天是 %d \n", today); // 输出 2printf("当前月份是 %d \n", currentMonth); // 输出 10printf("当前季节是 %d \n", currentSeason); // 输出 20printf("当前数字是 %d \n", num); // 输出 21// 修改枚举变量 today 的值为 FRIDAY// 枚举变量的值必须是该枚举类型中的一个枚举常量,不能是其他值。today = FRIDAY;printf("今天是 %d \n", today); // 输出 4// 修改枚举变量 num 的值为 100// 100 并不是枚举类型中的一个常量,这样做虽然不会报错,但失去了枚举的意义,不建议这么做num = 100;printf("当前数字是 %d \n", num); // 输出 100return 0;
}
3.4 案例演示 2:简化版枚举类型
尽管这种方式简洁,但枚举类型名称仍然存在,可以在后续代码中使用该类型定义更多的变量。
对于复杂的枚举类型或需要在多个地方使用同一枚举类型的场景,建议使用标准的定义方法(即先定义枚举类型,再定义变量),以提高代码的可维护性和可扩展性。
#include <stdio.h>int main()
{// 第一种方式:定义枚举类型并直接声明变量enum DAY{MON = 1,TUE,WED,THU,FRI,SAT,SUN} day1;// 初始化并使用枚举变量 day1day1 = WED;printf("今天是 %d \n", day1); // 输出 3// 修改 day1 的值day1 = FRI;printf("今天是 %d \n", day1); // 输出 5// 第二种方式:定义枚举类型并直接声明并初始化变量enum DAY2{MON2 = 1,TUE2,WED2,THU2,FRI2,SAT2,SUN2} day2 = TUE2;// 使用枚举变量 day2printf("今天是 %d \n", day2); // 输出 2// 第三种方式:定义枚举类型并一次性声明多个变量enum DAY3{MON3 = 1,TUE3,WED3,THU3,FRI3,SAT3,SUN3} day3,day4;// 初始化并使用枚举变量 day3 和 day4day3 = SAT3;day4 = SUN3;printf("今天是 %d \n", day3); // 输出 6printf("今天是 %d \n", day4); // 输出 7// 在后续代码中声明新的变量enum DAY anotherDay = SAT;printf("今天是 %d \n", anotherDay); // 输出 6return 0;
}
3.5 案例演示 3:匿名枚举类型
由于匿名枚举类型没有名称,因此不能在其他地方重新使用相同的枚举类型定义新的变量。每次需要使用时都需要重新定义整个枚举类型。
虽然匿名枚举类型可以减少一些冗余代码,但在大型项目中可能会影响代码的可读性和可维护性。建议在简单的情况下使用匿名枚举类型,而在复杂项目中使用带名称的枚举类型。
#include <stdio.h>int main()
{// 定义匿名枚举类型并同时声明多个枚举变量enum{MON = 1,TUE,WED,THU,FRI,SAT,SUN} day1,day2, day3 = WED; // 同时声明多个枚举变量,并初始化 day3// 初始化并使用枚举变量 day1 和 day2day1 = MON;day2 = FRI;// 输出 day1, day2 和 day3 的值printf("day1 是 %d \n", day1); // 输出 1printf("day2 是 %d \n", day2); // 输出 5printf("day3 是 %d \n", day3); // 输出 3// 修改 day1 和 day2 的值day1 = TUE;day2 = SAT;// 再次输出 day1 和 day2 的值printf("day1 是 %d \n", day1); // 输出 2printf("day2 是 %d \n", day2); // 输出 6// 在后续代码中声明新的变量enum{MON2 = 1,TUE2,WED2,THU2,FRI2,SAT2,SUN2} anotherDay = SUN2;printf("anotherDay 是 %d \n", anotherDay); // 输出 7return 0;
}
4 枚举的遍历
4.1 连续枚举常量的遍历
枚举常量的值如果是连续的,可以通过循环来遍历所有枚举常量。如果枚举常量的值不是连续的,则无法通过简单的循环来遍历,需要考虑其他方法。
#include <stdio.h>int main()
{// 定义枚举类型 WEEKDAY,表示星期一到星期天,值从 1 开始enum WEEKDAY{MONDAY = 1,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY};// 使用循环遍历出所有的枚举常量for (enum WEEKDAY day = MONDAY; day <= SUNDAY; day++){printf("星期 %d \n", day);}return 0;
}
输出结果如下所示:
4.2 非连续枚举常量的遍历
对于非连续的枚举常量,由于它们的值不是连续的,不能通过简单的循环来遍历。但是,可以通过以下几种方法来实现遍历:
4.2.1 手动遍历每个枚举常量
直接列出每个枚举常量并处理它们。
#include <stdio.h>int main()
{// 定义枚举类型 SEASON,表示北京地区一年四季的平均温度enum SEASON{SPRING = 18,SUMMER = 30,AUTUMN = 20,WINTER = -5};// 尝试遍历非连续的枚举常量// 注意:这种遍历方式是错误的,因为枚举常量的值不是连续的// 下面这个循环一次都不会执行。因为循环条件一直都不满足for (enum SEASON season = SPRING; season <= WINTER; season++){printf("季节 %d \n", season); // 不会执行}// 手动遍历每个枚举常量printf("季节 %d \n", SPRING);printf("季节 %d \n", SUMMER);printf("季节 %d \n", AUTUMN);printf("季节 %d \n", WINTER);return 0;
}
输出结果如下所示:
4.2.2 使用数组存储枚举常量
将枚举常量的值存储在一个数组中,然后遍历数组。
#include <stdio.h>int main()
{// 定义枚举类型 SEASON,表示北京地区一年四季的平均温度enum SEASON{SPRING = 18,SUMMER = 30,AUTUMN = 20,WINTER = -5};// 使用数组存储枚举常量的值enum SEASON seasons[] = {SPRING, SUMMER, AUTUMN, WINTER};int num_seasons = sizeof(seasons) / sizeof(seasons[0]);// 遍历数组for (int i = 0; i < num_seasons; i++){printf("季节 %d \n", seasons[i]);}return 0;
}
输出结果如下所示:
5 枚举在 switch 中使用
枚举可以与 switch 结合使用,通过枚举常量来控制不同的分支逻辑。以下是一个示例,展示了如何使用枚举和 switch 语句来处理用户输入的季节选择。
#include <stdio.h>int main()
{// 定义枚举类型 SEASONS,表示四个季节enum SEASONS{SPRING = 1, // 春天SUMMER, // 夏天AUTUMN, // 秋天WINTER // 冬天};// 定义枚举变量 seasonenum SEASONS season;// 获取用户输入printf("请输入你喜欢的季节: (1:spring, 2:summer, 3:autumn, 4:winter): ");scanf("%d", &season);// 使用 switch 语句判断用户输入的季节switch (season){case SPRING:printf("你喜欢的季节是春天。\n");break;case SUMMER:printf("你喜欢的季节是夏天。\n");break;case AUTUMN:printf("你喜欢的季节是秋天。\n");break;case WINTER:printf("你喜欢的季节是冬天。\n");break;default:printf("你没有选择你喜欢的季节。\n");break;}return 0;
}
在上面的示例中,使用 scanf 函数读取用户输入的整数值,并将其存储在枚举变量中。需要注意的是,用户输入的值必须是枚举常量的有效值,否则会进入 default 分支。
6 枚举数组
枚举数组是指数组的元素类型为枚举类型。通过定义枚举数组,可以方便地管理和操作一组枚举常量。以下是一些关于枚举数组的示例和解释。
#include <stdio.h>int main()
{// 定义枚举类型 SOLAR_TERMS,表示 24 节气enum SOLAR_TERMS{LICHUN = 1, // 立春YUSHUI, // 雨水JINGZHE, // 惊蛰CHUNFEN, // 春分QINGMING, // 清明GUYU, // 谷雨LIXIA, // 立夏XIAOMAN, // 小满MANGZHONG, // 芒种XIAZHI, // 夏至XIAOSHU, // 小暑DASHU, // 大暑LIQIU, // 立秋CHUSHU, // 处暑BAILE, // 白露QIUFEN, // 秋分HANLU, // 寒露SHUANGJIANG, // 霜降LIDONG, // 立冬XIAOXUE, // 小雪DAXUE, // 大雪DONGZHI, // 冬至XIAOHAN, // 小寒DAHAN // 大寒};// 定义一个枚举数组,存储多个节气enum SOLAR_TERMS terms[] = {LICHUN, YUSHUI, JINGZHE, CHUNFEN, QINGMING, GUYU,LIXIA, XIAOMAN, MANGZHONG, XIAZHI, XIAOSHU, DASHU,LIQIU, CHUSHU, BAILE, QIUFEN, HANLU, SHUANGJIANG,LIDONG, XIAOXUE, DAXUE, DONGZHI, XIAOHAN, DAHAN};// 获取数组的大小int num_terms = sizeof(terms) / sizeof(terms[0]);// 遍历枚举数组并输出每个节气for (int i = 0; i < num_terms; i++){switch (terms[i]){case LICHUN:printf("节气 %d: 立春\n", terms[i]);break;case YUSHUI:printf("节气 %d: 雨水\n", terms[i]);break;case JINGZHE:printf("节气 %d: 惊蛰\n", terms[i]);break;case CHUNFEN:printf("节气 %d: 春分\n", terms[i]);break;case QINGMING:printf("节气 %d: 清明\n", terms[i]);break;case GUYU:printf("节气 %d: 谷雨\n", terms[i]);break;case LIXIA:printf("节气 %d: 立夏\n", terms[i]);break;case XIAOMAN:printf("节气 %d: 小满\n", terms[i]);break;case MANGZHONG:printf("节气 %d: 芒种\n", terms[i]);break;case XIAZHI:printf("节气 %d: 夏至\n", terms[i]);break;case XIAOSHU:printf("节气 %d: 小暑\n", terms[i]);break;case DASHU:printf("节气 %d: 大暑\n", terms[i]);break;case LIQIU:printf("节气 %d: 立秋\n", terms[i]);break;case CHUSHU:printf("节气 %d: 处暑\n", terms[i]);break;case BAILE:printf("节气 %d: 白露\n", terms[i]);break;case QIUFEN:printf("节气 %d: 秋分\n", terms[i]);break;case HANLU:printf("节气 %d: 寒露\n", terms[i]);break;case SHUANGJIANG:printf("节气 %d: 霜降\n", terms[i]);break;case LIDONG:printf("节气 %d: 立冬\n", terms[i]);break;case XIAOXUE:printf("节气 %d: 小雪\n", terms[i]);break;case DAXUE:printf("节气 %d: 大雪\n", terms[i]);break;case DONGZHI:printf("节气 %d: 冬至\n", terms[i]);break;case XIAOHAN:printf("节气 %d: 小寒\n", terms[i]);break;case DAHAN:printf("节气 %d: 大寒\n", terms[i]);break;default:printf("未知节气\n");break;}}return 0;
}