讀古今文學網 > 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
)