C语言详解 枚举

C语言详解 枚举

2016年03月09日 23:12:07 源想传奇 阅读数:201

注:以下全部代码的执行环境为VC++ 6.0

在程序中,可能需要为某些整数定义一个别名,我们可以利用预处理指令#define来完成这项工作,您的代码可能是:

复制代码

#define MON  1
#define TUE   2
#define WED  3
#define THU   4
#define FRI    5
#define SAT   6
#define SUN   7

复制代码

 

在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型叫枚举型。

 

1. 定义一种新的数据类型 - 枚举型

 以下代码定义了这种新的数据类型 - 枚举型

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN    //此处的SUN可以写成SUN加逗号吗?即:SUN,??
};

 

(1) 枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开

(2) DAY是一个标识符,可以看成这个集合的名字是一个可选项(也就说当DAY省略后变成了enum{MON=1,TUE,WED,THU,FRI,SAT,SUN};后效果一样不能这样认为,效果一样是没有依据的,),

下面这句话的说法是我根据“使用typedef enum 定义的新类型为 workday和使用typedef enum WEEK定义的新类型名为  workday后,提示类型名重复的错误提示。”这句的理解得出的结论:

说明此时集合名可以是任意一个名都是一样的,也就说使用enum定义的 牧举类型包含了使用(enum 集合名)的类型,即:enum A类型,enum B类型, enum C 类型,enum D类型中的任何一个都是和使用enum这一项定义的类型是同一个类型,在一个程序中规定不能出现两个牧举类型相同的名字,也就是说只要在程序中有使用enum 这一项定义的类型后,就不能再存在其它类型的定义,譬如就不能出现:enum A类型,enum B类型, enum C 类型,enum D类型中的一个或多个,否则程序会报牧举类型名重复定义的错误。要想在程序中出现多个牧举类型的定义时,就一定不要使用enum 这一项来命名,只有使用enum再加一项即:enum dfd,   enum ffa 这样的形式来定义多个牧举类型才不会报错。),如果按照我的这样理解,那么下面的程序:在下面3.3 使用枚举型变量这部分中的两个定义结构体类型是重复的,运行会报错,既然能运行说明我的理解是错误的。:

3.3 使用枚举型变量

enum   //定义了牧举类型的集合,类型是enum ,集合中的元素有7个,没有定义变量。

    BELL          = '\a',   //为什么成员可以赋值为字符串呢?不是说成员的本质是整形吗?
    BACKSPACE = '\b',
    HTAB         = '\t',
    RETURN      = '\r',
    NEWLINE    = '\n', 
    VTAB         = '\v',
    SPACE       = ' '
};和

enum BOOLEAN { FALSE = 0, TRUE } match_flag;是不存在类型名重复的问题。因为他们没有使用typedef定义类型。

是错误的,既然能运行说明我的理解就是不对的。即是可有可无的项。

 

 

 

(3) 第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。(如果第二个成员设置整形为0,那么第一个成员的整形值是几?)(因为它的默认值整形,所以牧举类型的本质是int 类型,既然是整形,集合中的成员又是一些命名的整形常量,牧举类型定义的变量可以被赋值为这些整形常量,也可以是一些整形的数譬如30, 89等)

(4) 可以人为设定枚举成员的值,从而自定义某个范围内的整数。

(5) 枚举型是预处理指令#define的替代。

(6) 类型定义以分号;结束

 

2. 使用枚举类型对变量进行声明

新的数据类型定义完成后,它就可以使用了。我们已经见过最基本的数据类型,如:整型int, 单精度浮点型float, 双精度浮点型double, 字符型char, 短整型short等等。用这些基本数据类型声明变量通常是这样:

复制代码

char     a; //变量a的类型均为字符型char
char     letter;
int        x,
           y,
           z; //变量x,y和z的类型均为整型int
int       number;
double  m, n;
double  result; //变量result的类型为双精度浮点型double

复制代码

 

既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。

方法一:枚举类型的定义和变量的声明分开

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

 

enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY
enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY(可以同时定义多个变量

 

方法二:类型定义与变量声明同时进行

复制代码

enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
} workday; //变量workday的类型为枚举型enum DAY

复制代码

 

enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; //变量days的类型为枚举型enum week(week为牧举类型的集合名),牧举类型的集合可以横向书写,横向书写时可能不习惯,注意最后一个成员的后面要不要加逗号,可以编写程序时测试一下就知道了。这种书写习惯要适应。记住定义类型的同时定义变量时,大括号的后面不能加分号;

 

enum BOOLEAN { false, true } end_flag, match_flag; //定义枚举类型并声明了两个枚举型变量(BOOLEAN为牧举类型的集合名),此句代码可以写成:enum  { false, true } end_flag, match_flag;,这样也定义了两个牧举类型的变量:end_flag 和match_flag.

 

方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明:

复制代码

typedef enum workday
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
workday; //此处的workday为枚举型enum workday的别名

复制代码

 

workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday

 

enum workday中的workday可以省略:

复制代码

typedef enum
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
workday; //此处的workday为枚举型enum workday的别名

workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday(这个说法不正确,因为此时使用enum定义的牧举类型,这种定义的方法包含了:enum 集合名  ,这个集合名可以是任意的名称,所以上面的叫法:使用enum定义的类型怎么确定就是enum workday 呢?我也可以说它是enum xyz类型,也可以说说enum ppp类型,也可以说是enum bazzzhhhh类型。)

复制代码

 

也可以用这种方式:

复制代码

typedef enum workday  //这种情况要小心了,如何解析这种定义呢?首先使用了typedef 关键字,说明是类型的重命名,既然是类型重命名,就得有两个对象:一个是源类型名,另一个是重命名的新名称。这里出现了enum 和workday 两个对象,显然最后一个是新名称,推理第一个就是源类型名,所以enum 就是源类型名了。既然要来一个叫enum 的牧举类型名,那么下面的程序中就不能再出现牧举类型的定义了,否则就会出现类型名重复定义的错误提示。
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
};

workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday

复制代码

 

注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。错误示例如下所示:

错误声明一:存在同名的枚举类型  (只限于typedef enum  和typedef enum WEEK是一样的。)

复制代码

typedef enum   //此处等同于enum *,这里的*是万能适配符,也就是说enum = enum WEEK
{
    wednesday,
    thursday,
    friday
} workday;

typedef enum WEEK
{
    saturday,
    sunday = 0,
    monday,
} workday;

复制代码

 

错误声明二:存在同名的枚举成员

复制代码

typedef enum
{
    wednesday,
    thursday,
    friday
} workday_1;  //此处的牧举类型是workday_1

typedef enum WEEK
{
    wednesday,  //这一项会报错,因为在上面牧举类型定义时,成员名已经有一个名字叫wednesday了,程序中不能出现成员                           //名相同的成员。
    sunday = 0,
    monday,
} workday_2; //此处的牧举类型是workday_2  与上面的类型不相同。

复制代码

 

 

3. 使用枚举类型的变量

3.1 对枚举型的变量赋值。

实例将枚举类型的赋值与基本数据类型的赋值进行了对比:

方法一:先声明变量,再对变量赋值

复制代码

#include<stdio.h>

/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()
{
    /* 使用基本数据类型声明变量,然后对变量赋值 */
    int x, y, z;
    
    x = 10;
    y = 20;
    z = 30;  //基本类型的变量赋的值要与定义变量时的类型相同,如不同要进行强制类型转换才行,值是任意赋的,没有限制
    
    /* 使用枚举类型声明变量,再对枚举型变量赋值 */
    enum DAY yesterday, today, tomorrow;
    
    yesterday = MON;
    today     = TUE;
    tomorrow  = WED;//牧举类型的变量赋的值要与定义变量时的类型相同,如不同要进行强制类型转换才行,值是不是任意赋的(这句话不对,赋的值可以是表达式,这个表达式是集合元素参与运算的表达式,在表达式中可以加减任何的整数,也可以不是表达式,可以是一个整数譬如30赋值给变量today,),有限制,只能是牧举类型集合中的某一个值才行(这句话也不对)

    printf("%d %d %d \n", yesterday, today, tomorrow);
}

复制代码

 

方法二:声明变量的同时赋初值

复制代码

#include <stdio.h>

/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()
{
    /* 使用基本数据类型声明变量同时对变量赋初值 */
    int x=10, y=20, z=30;

    /* 使用枚举类型声明变量同时对枚举型变量赋初值 */
    enum DAY yesterday = MON, 
                        today = TUE,
                   tomorrow = WED;

    printf("%d %d %d \n", yesterday, today, tomorrow);
}

复制代码

 

方法三:定义类型的同时声明变量,然后对变量赋值。

复制代码

#include <stdio.h>

/* 定义枚举类型,同时声明该类型的三个变量,它们都为全局变量 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today, tomorrow;

/* 定义三个具有基本数据类型的变量,它们都为全局变量 */
int x, y, z;

void main()
{
    /* 对基本数据类型的变量赋值 */
    x = 10;  y = 20;  z = 30;
    
    /* 对枚举型的变量赋值 */
    yesterday = MON;
    today     = TUE;
    tomorrow  = WED;

    printf("%d %d %d \n", x, y, z); //输出:10 20 30
    printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}

复制代码

 

方法四:类型定义,变量声明,赋初值三个任务同时进行。

复制代码

#include <stdio.h>

/* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */
enum DAY
{
    MON=1, 
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN 
}
yesterday = MON, today = TUE, tomorrow = WED;

/* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */
int x = 10, y = 20, z = 30;

void main()
{
    printf("%d %d %d \n", x, y, z); //输出:10 20 30
    printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}

复制代码

 

3.2 对枚举型的变量赋整数值时,需要进行类型转换。(也就说当给牧举的变量赋值的表达式不是纯集合中的元素时,也就说赋的值是含有集合中元素的运算的表达式时,记住一定要把它转换成牧举类型,因为等号左边的变量是牧举类型,所以等号右边的表达式运算后不能确定是牧举类型,因此必须在表达式前面加上牧举类型(即:牧举类型的变量=enum  集合名(表达式))进行强制转换才行)

复制代码

#include <stdio.h>

enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()
{
    enum DAY yesterday, today, tomorrow;

    yesterday = TUE;
    today = (enum DAY) (yesterday + 1); //类型转换,today为牧举类型enum DAY的变量;(yesterday + 1)为要给变量赋的值,

                                                              // (enum DAY) 为对表达式进行强制类型转换成与变量类型相匹配的类型
    tomorrow = (enum DAY) 30; //类型转换//变量的值不是集合的值,所以上面我说的牧举类型的变量必须赋的值是集合中的值是不对的。
    //tomorrow = 3; //错误

    printf("%d %d %d \n", yesterday, today, tomorrow); //输出:2 3 30
}

复制代码

 

3.3 使用枚举型变量

复制代码

#include<stdio.h>

enum   //定义了牧举类型的集合,类型是enum ,集合中的元素有7个,没有定义变量。程序员定义此牧举类型的作用是将来在下面的程序代码中使用判断字符串语句是否有空格和printf()输出时要有回车,换行 的意思时,提前用牧举类型的形式把成员定义成字符的形式,这就说明牧举类型中的成员赋值时不一定是整形的值,可以是字符,设置成整形就是整形,设置成字符型就是字符类型的常量,其实字符型也是整形。

    BELL          = '\a',   //为什么成员可以赋值为字符串呢?不是说成员的本质是整形吗?
    BACKSPACE = '\b',
    HTAB         = '\t',
    RETURN      = '\r',
    NEWLINE    = '\n', 
    VTAB         = '\v',
    SPACE       = ' '
};

enum BOOLEAN { FALSE = 0, TRUE } match_flag;  //又定义了一个牧举类型enum BOOLEAN,与上面的牧举类型不是重复了吗?没有重复,说重复是自己在这里把以前使用typedef定义类型的情况给搞混了。这里值定义了一个变量match_flag.

void main()
{
    int index = 0;
    int count_of_letter = 0;
    int count_of_space = 0;

    char str[] = "I'm Ely efod";   //定义了上面4个变量,3个int类型,1个字符数组类型

    match_flag = FALSE;   //意思是将数字0赋值给变量match_flag

    for(; str[index] != '\0'; index++)//当字符数组的元素不等于字符串结束符'\0'时,就进入循环体执行下面的语句,否则就执行下面的第一个printf语句。此处好像漏掉了一个for循环的大括号{}。
        if( SPACE != str[index] )//假如取得字符串中的元素不等于空格(即SPACE的值)时,变量count_of_letter就加1,假如等于空格,就跳出循环执行else里面的语句()
            count_of_letter++;//此变量存储的是字符串数组中元素的个数
        else
        {
            match_flag = (enum BOOLEAN) 1;//将数字1赋值给变量match_flag,当然要进行强制类型转换成牧举类型:enum BOOLEAN,因为数字1的类型是int 类型,变量match_flag是牧举类型:enum BOOLEAN.这句的作用是什么呢?看下面的代码再说。
            count_of_space++;  //存放的是空格的个数。或者说是存放空格的次数
        }
    
    printf("%s %d times %c", match_flag ? "match" : "not match", count_of_space, NEWLINE);// match_flag ? "match" : "not match"是运用了三目运算符,如果表达式的值是真则输出就是第一个字符串,不是真就输出第二个字符串,

  //printf("%s %d times %c", match_flag ? "match" : "not match", count_of_space, '\n');
    printf("count of letters: %d %c%c", count_of_letter, NEWLINE, RETURN);

 //printf("count of letters: %d %c%c", count_of_letter, '\n', '\r');
}

复制代码

 

输出:
match 2 times  //输出字符串数组中匹配空格的次数,或者说输出字符串数组中空格的个数
count of letters: 10//输出字符串数组中字符的个数。其字符的值分别是 I ' m  E l y  e f o d 这10个字符,包含撇字符'
Press any key to continue

 

4. 枚举类型与sizeof运算符

复制代码

#include <stdio.h>

enum escapes

    BELL      = '\a',
    BACKSPACE = '\b',
    HTAB      = '\t',
    RETURN    = '\r',
    NEWLINE   = '\n', 
    VTAB      = '\v',
    SPACE     = ' '
};

enum BOOLEAN { FALSE = 0, TRUE } match_flag;

void main()
{
    printf("%d bytes \n", sizeof(enum escapes)); //4 bytes//牧举类型开辟的空间
    printf("%d bytes \n", sizeof(escapes)); //4 bytes//集合名的空间

    printf("%d bytes \n", sizeof(enum BOOLEAN)); //4 bytes
    printf("%d bytes \n", sizeof(BOOLEAN)); //4 bytes
    printf("%d bytes \n", sizeof(match_flag)); //4 bytes//牧举类型定义的变量空间

    printf("%d bytes \n", sizeof(SPACE)); //4 bytes//牧举类型定义的集合中的成员的空间
    printf("%d bytes \n", sizeof(NEWLINE)); //4 bytes
    printf("%d bytes \n", sizeof(FALSE)); //4 bytes
    printf("%d bytes \n", sizeof(0)); //4 bytes////牧举类型定义的集合中的成员的的值的空间

//下面的测试又是什么结果呢?

  printf("%d bytes \n", sizeof('\a'));

 printf("%d bytes \n", sizeof('\b')); 

 printf("%d bytes \n", sizeof('\t'));

 printf("%d bytes \n", sizeof('\r'));

 printf("%d bytes \n", sizeof('\n'));

printf("%d bytes \n", sizeof('\v'));

 printf("%d bytes \n", sizeof(' '));
}

复制代码

 

5. 综合举例

复制代码

#include<stdio.h>

enum Season
{
    spring, summer=100, fall=96, winter
};

typedef enum
{
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
Weekday;

void main()
{
    /* Season */
    printf("%d \n", spring); // 0,如果将summer设置成 summer = 0后,再测试spring的是多少呢?
    printf("%d, %c \n", summer, summer); // 100, d
    printf("%d \n", fall+winter); // 193//因为fall的值是96,则winter的值是97,则fall+winter= 193

    Season mySeason=winter;//97赋值给变量myseason
    if(winter==mySeason)
        printf("mySeason is winter \n"); // mySeason is winter
    
    int x=100;
    if(x==summer)
        printf("x is equal to summer\n"); // x is equal to summer

    printf("%d bytes\n", sizeof(spring)); //整形的成员的空间是 4 bytes

    /* Weekday */
    printf("sizeof Weekday is: %d \n", sizeof(Weekday)); //sizeof Weekday is: 4,测试变量Weekday的空间

    Weekday today = Saturday;//将Saturday 的值5赋值给成员新定义的变量today
    Weekday tomorrow;  //新定义一个变量tomorrow
    if(today == Monday)  //判断Monday的值0是不是和today的值5相等,显然不相等
        tomorrow = Tuesday;
    else
        tomorrow = (Weekday) (today + 1); //remember to convert from int to Weekday意思是要把(today+1)转换成tomorrow定义时的类型:Weekday,做到类型匹配。
}

复制代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值