映月读书网 > C语言解惑 > 10.2 枚举 >

10.2 枚举

在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等。如果把这些量说明为整型、字符型或其他类型,显然都是不妥当的。为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。

应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型(它不能再分解为任何基本类型),只是枚举的定义与结构的定义十分相似而已。

用关键字enum来表示枚举,枚举是一个被命名为整数常数的集合,这些常数指定了所有的类型已被定义的合法值。其一般形式为:


enum
 枚举名 { 
枚举表 }
 变量表;
  

枚举名和变量表是选择项。例如定义一个coin的枚举,money属于这种类型。


enum coin { penny
, nickel
, dime
, quarter
, half_dollar
, dollar }
;
enum coin money
;
  

除非进行了初始化,否则第一个枚举符号的值为0,第二个为1,依次类推。因此


printf 
( \"%d %d \"
, penny
, dime 
);
  

将在屏幕上显示0和2两个值。由此可见,一个枚举其实是将每个符号用它们所对应的整数来代替。例如:


printf 
( \"The number of nickel in a quarter is %d\"
, quarter+2 
);
  

按enum定义,quarter=3,所以quarter+2=5。输出为:


The number of nickel in a quarter is 5
  

【例10.5】找出下面程序中的错误。


#include <stdio.h>
enum weekday{ sun
,mou
,tue
,wed
,thu
,fri
,sat }a
;
void main
()
{
     sun=5
;
     thu=1
;
     printf 
( \"wed is %dn\"
, wed 
);
     printf 
( \"sat is %dn\"
, sat 
);
}
  

【解答】枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。


//
改正的程序
#include <stdio.h>
enum weekday{ sun = 5
,mou
,tue
,wed
,thu = 1
,fri
,sat }a
;
void main
()
{
     printf 
( \"wed is %dn\"
, wed 
);
     printf 
( \"sat is %dn\"
, sat 
);
}
  

程序运行结果如下:


wed is 8
sat is 3
  

【例10.6】找出下面程序中的错误。


#include <stdio.h>
enum weekday{ sun
,mou
,tue
,wed
,thu
,fri
,sat }a
,b
,c
;
void main
()
{
     a=\"mou\"
;
     b=\"wed\"
;
     c=\"fri\"
;
     printf 
( \"a is %dn\"
, a 
);
     printf 
( \"b is %dn\"
, b 
);
     printf 
( \"c is %dn\"
, c 
);
}
  

【解答】枚举元素是整型常量,既不是字符常量,也不是字符串常量,所以使用时不能加单或双引号。


//
改正的程序
#include <stdio.h>
enum weekday{ sun
,mou
,tue
,wed
,thu
,fri
,sat }a
,b
,c
;
void main
()
{
   a=mou
;
   b=wed
;
   c=fri
;
   printf 
( \"a is %dn\"
, a 
);
   printf 
( \"b is %dn\"
, b 
);
   printf 
( \"c is %dn\"
, c 
);
}
  

运行结果如下:


a is 1
b is 3
c is 5
  

【例10.7】下面的程序是否正确?


#include <stdio.h>
enum weekday{ sun
,mou
,tue
,wed
,thu
,fri
,sat }a
,b
,c
;
void main
()
{
   a=1
;
   b=3
;
   c=5
;
   printf 
( \"a is %dn\"
, a 
);
   printf 
( \"b is %dn\"
, b 
);
   printf 
( \"c is %dn\"
, c 
);
}
  

【解答】视编译系统而定。有的系统允许把数值直接赋予枚举变量,而有的系统不允许这样赋值。如一定要把数值赋予枚举变量,则必须用强制类型转换。下面两种语句


b=
(enum weekday
)3
;  
b=
(enum 
)3
;  
  

都可将数值3赋给枚举变量b,也就是将序号为3的枚举元素赋予枚举变量b,相当于语句


b=wed
;
  

【例10.8】分析下面程序的输出结果。


#include <stdio.h>
enum fiv { a
,b
,c
,d
,e} m[15]
, j
;
void main
()
{
     int i
;
     j=a
; 
     for
(i=0
;i<15
;i++
){
         m[i]=j
;
         j++
;
         if 
(j>e
)  j = a
;
     }
     for
(i=0
;i<15
;i++
){
         switch
(m[i]
)
         {
             case a
:
                      printf
(\" %2d  %ct\"
,i
,\'a\'
);
                      break
;         
             case b
:
                      printf
(\" %2d  %ct\"
,i
,\'b\'
);
                      break
;         
             case c
:
                      printf
(\" %2d  %ct\"
,i
,\'c\'
);
                      break
;         
             case d
:
                      printf
(\" %2d  %ct\"
,i
,\'d\'
); 
                      break
;  
             case e
:
                      printf
(\" %2d  %cn\"
,i 
,\'e\'
);
                      break
;
            default
:
                     break
;
         }
     }
}
 

【解答】m是枚举数组,下标也是从0开始。为它赋值是从0开始,依次到e,也就是4。然后从0开始再次循环赋值。下标和值的关系如下:


下标0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
值0 1 2 3 4 0 1 2 3 4 0  1  2  3  4
  

switch用m数组的值作为跳转依据。m有5个不同的值,对应a,b,c,d,e,打印循环的i值是0~14,并5个一组分别对应字符a,b,c,d,e。由此可以给出如下输出结果。


 0  a    1  b    2  c    3  d    4  e
 5  a    6  b    7  c    8  d    9  e
10  a   11  b   12  c   13  d   14  e
  

【例10.9】编写一个简单的从给定2014年某日得到星期几的程序,要求输入和输出的格式如下:


Input month day
:5 25
today is sun
(7
)
  

【解答】使用枚举


enum weekday{ mou=1
, tue
, wed
, thu
, fri
, sat
, sun} 
;
  

定义星期一至星期天,为了兼顾习惯,将周一初始化为1,则周日为7。

因为只考虑2014年全年,这就可以简单地从2014年1月1日是星期几作为依据进行编程。假设给定的月为month,日期为day,先计算month-1的天数,再加上本月的day-1天,就是总天数alldays。求星期几是用%7,但这没有考虑1月1日已经是星期几的条件。假设1月1日为origin_day,则((alldays+origin_day)%7)就得到星期几。注意在枚举中定义星期天为7,这里计算的星期天是0,所以需要转换。可以继续使用已有变量alldays,使用


alldays = 
((alldays + origin_day
) % 7
);
if 
(alldays == 0
) return 7
;
  

语句即可实现。“return alldays”可以满足其他6天。

输出可以设计一个函数


void print_today
(today
)
  

来实现。使用switch将7种情况区分开来即可实现各自的输出。下面给出完整的程序。


#include <stdio.h>
enum weekday get_weekday
(int
, int
);
void print_today
(int
);
enum weekday{ mou=1
, tue
, wed
, thu
, fri
, sat
, sun}
;
void main
()
{
   int month
, day
;
   enum weekday today
;
   printf
(\"Input month day
:\"
);
   scanf
(\"%d%d\"
, &month
, &day
);
   today =     get_weekday
(month
, day
);
   print_today
(today
);
}
enum weekday get_weekday
(int month
, int day
)
{
   int m[12] = { 31
, 28
, 31
, 30
, 31
, 30
, 31
, 31
, 30
, 31
, 30
, 31 }
;
   int i=0
,  alldays = 0
, origin_day = 3
;
   for
( i=1
; i < month
; i++
)
   {
         alldays += m[i-1]
;
   }
   alldays += day-1
;
   alldays = 
((alldays + origin_day
) % 7
);
   if 
(alldays == 0
) return 7
;
   return alldays
;
}
void print_today
(int today
)
{
   switch
(today
)
   {
       case 1
:
                 printf
(\"today is %s
(%d
)n\"
, \"mou\"
,today
);
                 break
;
       case 2
:
                 printf
(\"today is %s
(%d
)n\"
, \"tue\"
,today
);
                 break
;
       case 3
: 
                printf
(\"today is %s
(%d
)n\"
, \"wed\"
,today
);
                 break
;
       case 4
: 
               printf
(\"today is %s
(%d
)n\"
, \"thu\"
,today
);
               break
;
       case 5
: 
               printf
(\"today is %s
(%d
)n\"
, \"fri\"
,today
);
               break
;
       case 6
: 
               printf
(\"today is %s
(%d
)n\"
, \"sat\"
,today
);
               break
;
       case 7
: 
               printf
(\"today is %s
(%d
)n\"
, \"sun\"
,today
);
               break
;
   }
}
  

程序运行示范如下:


Input month day
:1 1
today is wed
(3
)
Input month day
:2 14
today is fri
(5
)
Input month day
:3 8
today is sat
(6
)
Input month day
:5 25
today is sun
(7
)
Input month day
:8 5
today is tue
(2
)
Input month day
:11 24
today is mou
(1
)
Input month day
:12 31
today is wed
(3
)