1.4 复合数据类型和枚举类型

逗比:呜啦啦啦啦啦~呜啦啦啦拉拉~各位小伙伴们大家好呀,欢迎来到暴走大……
棒槌:CUT!
逗比:哈?怎么了?第五季的出场不够帅?
棒槌:我说你拿错剧本了吧……
逗比:哦?是吗?啊呀!!!还真是咧,这是圣诞老王的剧本……
棒槌:我说你是来逗比的吗?
逗比:咳咳,明明是你昨天嫌我太正经,要我逗比一点的,一点都不体谅人家的辛苦。
棒槌:本来就是,你去看看你同时更新那个操作系统的文章,简直就是领导讲话,一点都不好玩。
逗比:你也拜托,那个系列只不过是我的学习笔记,又不是教程,干嘛要弄得那么逗比。
棒槌:可是我也想学啊,你不弄逗比点我看不进去学不会。
逗比:行行行,自己棒槌还赖我,你也别那么着急去学操作系统内核,C语言的功底特别重要,你先好好跟着我把C语言搞明白的再想别的哈。
棒槌:说谁棒槌呢,你个逗比,赶紧的,我一年前的问题你还没解决呢,后来就跑得没影了,现在该给我们介绍了吧。
逗比:好的好的,虽然我一年没来,不过你的问题我还是记得的,你当时是问,如果我想表示一个学生的基本信息,那用基本数据类型会很不方便,那么我们应该怎么办。
棒槌:记得都不说早点回来给我解答,一点都没有当老师的责任感……
逗比:我们就拿一个学生的信息表示来举例,一个学生,他应该有姓名、性别、年龄、学号等的信息,由于姓名这一属性需要用到字符串,这个我们后面再谈,所以呢,我们目前就仅仅来实现学校、性别和年龄这三个属性。
棒槌:又避开话题……算了,你继续说吧。
逗比:首先来说性别,性别这一属性当然可以用整型,你可以规定0表示男,1表示女,但是,如果出于某种原因……
棒槌:什么原因?
逗比:什么原因?比如说这哥们突然棒槌了,或者那一天出去关门的时候没注意,把自己脑袋给夹了……之类的。
棒槌:(吐血)
逗比:这个时候,如果你给性别这个属性赋值个2呀3呀或者100000之类的,程序其实是不会有任何问题的,但是这个程序要是运行出来肯定就比较傻了,因为你这第三个性别第四个性别就算能理解,这第几十万个性别貌似就有点说不过去了,但是,由于你使用整型,对这个变量的取值是没有做特殊要求的,这就很容易让人给它赋一个没有意义的值。
棒槌:真逗,你以为读你程序的人都是棒槌啊?
逗比:这种事情谁能说得准呢,你看,现在不就有个棒槌在看我的程序。
棒槌:谁呀?谁呀?
逗比:好了,所以,我们还是应该更加明示一下这个变量具体表示的意思,虽然对于计算机来说它就是整型,但是,我们应当让提示一下读程序的人(这个人很有可能就是你自己,因为写多了的话肯容易把之前的忘掉)这个变量其实表示的是什么,所以,我们就给整型再起一个别名,这样做的好处是,提示程序员它实际表示的是什么,与此同时,计算机会仍然把它当做整型来对待。
typedef int Sex;
Sex stu_sex = 0;
逗比:相当于给int又起了个名字叫Sex,所以你写Sex stu_sex其实就相当于写了int stu_sex,但这样意义更加明确,至少程序员知道这个变量是表示性别的了。
棒槌:可是就算是这样,还是没有解决你刚说的问题啊,我还是不能从这个Sex直接判断出来我是应该赋值0呢还是1呢还是2呢还是10000呢……
逗比:没错,这样做确实还没有解决问题,我们仅仅是知道用它表示性别,但还是不知道到底用哪两个数来表示男女,所以,继续给出解决方案,这就是枚举类型。
棒槌:美剧?美剧不好看啦,我喜欢韩剧。
逗比:我还日剧呢,拜托你听清楚好不好,是枚举,不是美剧,我的普通话应该很标准的吧。
棒槌:切~还说自己是逗比呢,一点都不懂美式幽默……
逗比:自己讲了个冷笑话还好意思说我。好了,继续说,我们刚才是给数据类型起了别名,而枚举类型相当于连同数值也起了别名,我们可以给出某一枚举类型的有限个取值,而至于每个取值究竟对应哪个整数,那就是我们自己说了算了。
棒槌:不懂,完全不懂。
逗比:好吧,不懂没关系,来看个例子吧,这次我就不用性别了,我用一年四季来举一个栗子。
棒槌:栗子!
逗比:喂!你是花栗鼠吗?还随身带栗子……到底谁是来逗比的啊……
enum season {
    seasonSpring = 1,
    seasonSummer = 2,
    seasonAutumn,
    seasonWinter
};
enum season s1 = seasonSummer;

棒槌:噢噢噢噢,我看明白了,你创造了一个新的类型叫season,然后呢,这个类型只有这4个取值是不是啊。
逗比:额……其实呀,你的这种理解是有道理的,因为很多教材上就是这么来解释枚举的,但是吧,还真不太对。
棒槌:教材上的不对,你的就对,哪来的自信啊。
逗比:我没说这种解释不对,因为通常针对于新手来说,这样可以帮助理解,但是,这种理解其实是更接近于程序员的思维上的理解,换句话说,你以后在写程序的时候确实可以这么认为,但是,我还是希望咱们大家能够明白底层的实现,也就是说,我们要学会用计算机的思维来想这件事情,如果用计算机的方式来说的话,那刚才这个解释就真的不对了。
棒槌:好吧,虽然你刚才说教材错了这一点我很鄙视你,不过你还是继续讲吧。
逗比:明明被我说动了……口是心非的家伙。好吧,我继续来说。其实呢,枚举类型并不能算是一种新的类型,它本质上还是整型,所以假如说你给s1赋值一个8也是完全没问题的,你用printf()来打印也一样出整数,只不过,程序员在给它赋值的时候,可以直接写seasonSpring,而并不需要去管这个取值对应的到底是哪个整数了。棒槌你听懂没?
棒槌:基本上算是明白了吧,不过还有一个问题,你看你给春天指定了一个1,给夏天指定了一个2,后面那俩你没指定数啊,那应该是多少呢?
逗比:这个问题问的相当好!虽然说我们可以给每个枚举的取值取一个对应的数值,但是,如果我们不写的话是有默认值的,就比如说上面,我们给夏天指定了2,秋天没有写,就会默认3,冬天就会默认4。而如果我们全部都没有写的话,最开头的一个就会默认0。
棒槌:那如果这么说的话,seasonSummer后面的2其实也可以不用写的吧。
逗比:没错。
棒槌:好了,会了。
逗比:真会了?
棒槌:那可不,我这么有才华,智商这么高~
逗比:那我考考你,敢不敢?
棒槌:放马过来吧~
逗比:稍微一不注意就开始嘚瑟,看我让你个棒槌现原形。那我问你,既然我已经给枚举名起名是season了,它的成员为什么还要用season前缀,我直接写spring,summer这样不可以么?
棒槌:这个啊……这个嘛……我当然知道了,因为这样可以显得高大上!
逗比:棒槌~你写程序是为了装X啊。不会就说不会,以后不要还没学完就开始嘚瑟。
棒槌:行行行,我错了,你赶紧讲吧。
逗比:这里是一个明明规范,这里我们一年四季可能大家都不会理解成别的,但是,更多的时候,只是给你一个枚举取值,我们是不知道它属于哪个类型中的,因此,把枚举名作为取值的前缀更加方便我们阅读和使用。另外要说明的一点是,enum XXX {...}这整个都是一个类型,你是可以给后面直接声明变量的,比如说
enum Sex {
    sexMale,
    sexFemale
} s1, s2;
所以,分号是结束标记,即便你后面没有跟变量,也得有分号,这个千万别忘了。还有一个要说的就是,enum season整体作为一个类型名称,不能光写一个season。
棒槌:麻烦死了~~~我觉得每次都写enum太麻烦了,看着还累,你看看我这么着行不行。
typedef enum season Season;
Season s4 = seasonSpring;
逗比:哎哟喂~我说真的难得你能正经一回。非常非常不错,就用我刚才讲的typedef重新命名一下就可以去掉这个enum关键字。顺便说一下,写一个enum的声明,然后用typedef,这两句可以合二为一来写,就像这样:
typedef enum season {
    seasonSpring,
    seasonSummer,
    seasonAutumn,
    seasonWinter
} Season;
我们把enum的主体嵌套在typedef中,这样分号前的就不是变量了,而是重命名后的名称,这样你写enum season或者写Season都可以。当然,还有一种更加简洁的方法,就是使用匿名枚举,所谓匿名就是没有名字,用整个主体作为类型声明,再配合上typedef,这也是我建议大家的写法,以后枚举类型都可以这么去写:
typdef enum {
    sexMale,
    sexFemale
} Sex;
顺便一提,使用typedef重命名后的名字,一般用大驼峰,首字母大写,这也是一种命名规范。
棒槌:O了,这个我完全懂了,继续吧。
逗比:好的,解决了性别问题,年龄和学号用整型就可以了,接下来的任务就是怎么把它们结合一起,以前的方法是用三个变量分别表示,但这样很麻烦,操作起来还容易出错,并且,这些变量应该是绑定性的,不是分散的,它们应该统一处理,由此我们引入了结构体,和枚举非常类似,但它属于一个复合类型,由于刚才我们有了枚举类型的功底了,这里我就不再进行变形的演变,直接写出最终版:
typedef enum {
    sexMale,
    sexFemale
} Sex;
typedef struct {
    int number;
    int age;
    Sex sex;
} Student;
注意结构体成员以分号结尾,不像枚举那样用逗号隔开。结构体的三个成员是绑定的,我们每定义一个Student类型变量,就相当于定义了三个变量,下面是一个举例:
Student s1; // 定义变量
s1.number = 1; // 用点运算符访问成员
s1.age = 21;
s1.sex = sexMale;
无论是读取还是写入这个变量的成员,都用点运算符(就是英文的句号)。用点运算相当于操作了这个结构体变量的某一部分,当然它也可以整体操作,比如:
Student s2 = s1; // 整体赋值
结构体中可以嵌套枚举,自然,结构体里也可以嵌套结构体,比如说:
struct s1 {
    struct {
        int s11, s12;
    } s1;
    int s2;
};
struct s1 va1; // 定义变量
va1.s1.s11 = 0; // 给成员的成员赋值
va1.s1.s12 = 2;
va1.s2 = 8;

好啦,多的栗子不举了,棒槌你应该会了吧。
棒槌:举栗子!
逗比:这人绝对绝对是花栗鼠变得,我可告诉你,结构体你学这么快,不代表你后面学得快,下节课我要讲指针,这可是几乎所有刚入门的小伙伴都头疼的东西,你可要做好准备!
棒槌:就我还怕这个?凭我的聪明才智,看我分分钟给你搞定!栗子栗子栗子!
逗比:哎~~哎~~你那栗子不打算分我点啊,我给你讲这么半天都不说慰问我一下。哎~~别跑~~




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章