11.1-1枚举
常量符号化
- 用符号而不是具体的数字来表示程序中的数字
#include
constintred=0;
constintyellow=1;
constintgreen=2;
intmain(intargc, charconst*argv[])
{
intcolor=-1;
char*colorName=NULL;
printf("请输入你喜欢的颜色的代码:");
scanf("%d",&color);
switch( color ){
casered:colorName="red";break;
caseyellow:colorName="yellow";break;
casegreen:colorName="green";break;
default:colorName="default";break;
}
printf("你喜欢的颜色是%d",colorName);
return0;
}
枚举
- 用枚举而不是定义独立的const int变量
#include
enumCOLOR{RED,YELLOW,GREEN}; //枚举
intmain(intargc, charconst*argv[])
{
intcolor=-1;
char*colorName=NULL;
printf("请输入你喜欢的颜色的代码:");
scanf("%d",&color);
switch( color ){
caseRED:colorName="red";break;
caseYELLOW:colorName="yellow";break;
caseGREEN:colorName="green";break;
default:colorName="default";break;
}
printf("你喜欢的颜色是%d",colorName);
return0;
}
- 枚举是一种用户定义的数据类型,它用关键字enum 以如下语法来声明:
- enum 枚举类型名字{名字0,.....,名字n};
- 枚举类型名字可以省略
- 枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n。如:
- enum colors{red,yellow,green};
- 这样就创建了3个常量,red的值是0,yellow的值是1,而green的值是2
- 当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量名字
#include
enumcolor{ red,yellow,green};
voidf(enumcolorc);
intmain(void)
{
enumcolort=red;
scanf("%d",&t);
f(t);
return0;
}
voidf(enumcolorc)
{
printf("%d\n",c);
}
- 枚举量可以作为值
- 枚举类型可以跟上enum作为类型
- 但是实际上是以整数来做内部计算和外部输入输出的
#include
enumCOLOR{RED,YELLOW,GREEN,NumCOLOR};
intmain(intargc, charconst*argv[])
{
intcolor=-1;
char*ColorNames[NumCOLOR] = {"red","yellow","green",};
char*colorName=NULL;
printf("请输入你喜欢的颜色的代码:");
scanf("%d",&color);
if( color>=0&&color<NumCOLORS ){
colorName=ColorNames[color];
}else{
colorName="unknown";
}
printf("你喜欢的颜色是%s",colorName);
return0;
}
- 这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便
- 上面的套路:在进行枚举的时候最后面在放上一个数(NumCOLORS),这样就能够表示NumCOLORS前面有几个数了(例如里面有3个数,索引值到0-2,在后面加上一个数,索引值刚好等于实际我们想要表达的数量)
枚举量
- 声明变量可以指定值
- enum COLOR{RED = 1,YELLOW,GREEN = 5};
#include
enumCOLOR {RED=1; YELLOW,GREEN=5,NumberCOLORS};
intmain(intargc,charconst*argv[])
{
printf("code for GREEN is %d\n",GREEN);
return0;
}
//这样输出的话,会从1开始计数,YELLOW则变成1+1,然后到GREEN的5之前都会跳过了
枚举只是int
- 即使给枚举类型的变量赋不存在的整数值也没有任何warning或error
枚举
- 虽然枚举类型可以当作类型使用,但是实际上很(bu)少(hao)用
- 如果有意义上排比的名字,用枚举比const int方便
- 枚举比宏(macro)好,因为枚举有int类型,宏没有类型(宏我在后面会解释是啥)
11.2-1结构类型
声明结构类型
#include
intmain(intargc,charconst*argv[])
{
structdate{
intmonth;
intday;
intyear;
};//声明在这里,最后要加上分号哦,这是在函数内部声明的,通常放在函数外面
structdatetoday;//在这里我们定义了一个变量是today,类型是struct date的
today.month=07;
today.day=31;
today.year=2014;
printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);
return0;
}
//声明结构类型跟定义结构变量是两件事情哦
- 声明在函数内还是函数外?
- 和本地变量一样(就是局部变量),在函数内部声明的结构类型只能在函数内部使用
- 所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了
structpoint{
intx;
inty;
};
structpointp1,p2;
p1和p2都是point
里面有x和y值//这是第一种声明方式
----------------------------------------------
struct{
intx;
inty;
}p1,p2;
p1和p2都是一种无名结构,里面有x和y //这是第二种形式,没有名字(没有声明point)
//只是定义了两个变量,因为作者并不打算接下来继续在其他地方去调用
--------------------------------------------------------
structpoint{
intx;
inty;
}p1,p2;
p1和p2都是point,里面有x和y的值t //这是第三种声明方式
结构的初始化
#include
structdate{
intmonth;
intday;
intyear;
};
intmain(intargc,charconst*argv[])
{
structdatetoday= {07,31,2014};
structdatethismonth= {.month=7,.year=2014};
printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);
printf("This month is %i-%i-%i.\n",thismonth.year,thismonth.month,thismonth.day);
//给的值会被填进去,没给的值跟数组一样默认为0
return0;
}
结构成员
- 结构和数组有点像
- 数组用[]运算符和下标访问其成员
- a[0] = 10;
- 结构用.运算符和其名字访问其成员
- today.day
- student.firstName
- p1.x
- p2.y
结构运算
- 要访问整个结构,直接用结构变量的名字
- 对于整个结构,可以做赋值、取地址,也可以传递给函数参数
- p1 = (struct point){5,10}; //相当于p1.x = 5;p1.y = 10;
- p1 = p2; //相当于p1.x = p2.x;p1.y = p2.y;
- 数组无法做这两种运算!但结构可以
结构指针
- 和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
- struct date *pDate = &today;
#include
structdate{
intmonth;
intday;
intyear;
};
intmain(intargc,charconst*argv[])
{
structdatetoday;
today= (structdate){07,31,2014};
structdateday;
structdate*pDate=&today; //指向地址
printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);
printf("The day's date is %i-%i-%i.\n",day.year,day.month,day.day);
printf("address of today is %p\n",pDate);
return0;
}
11.2-2结构与函数
结构作为函数参数
int numberOfDays(struct date d)
- 整个结构可以作为参数的值传入函数
- 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
- 也可以返回一个结构
- 跟数组完全不一样
#include
#include
structdate{
intmonth;
intday;
intyear;
};
boolisLeap(structdated);
intnumberOfDays(structdated);
intmain(intargc,charconst*argv[]){
structdatetoday,tomorrow;
//输入今天的日期,月 日 年
printf("Enter today's date (mm dd yyyy):");
scanf("%i %i %i",&today.month,&today.day,&today.year);
if( today.day!=numberOfDays(today)){
tomorrow.day=today.day+1;
tomorrow.month=today.month;
tomorrow.year=today.year;
}elseif( today.month==12 ){
tomorrow.day=1;
tomorrow.month=1;
tomorrow.year=today.year+1;
}else{
tomorrow.day=1;
tomorrow.month=today.month+1;
tomorrow.year=today.year;
}
printf("Tomorrow's date is %i-%i-%i.\n",
tomorrow.year,tomorrow.month,tomorrow.day);
return0;
}
intnumberOfDays(structdated){
intdays;
constintdaysPerMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if(d.month==2&&isLeap(d))
days=29;
else
days=daysPerMonth[d.month-1];
returndays;
}
boolisLeap(structdated){
boolleap=false;
if((d.year%4==0&&d.year%100!=0) ||d.year%400==0 )
leap=true;
returnleap;
}
输入结构
- 没有直接的方式可以一次scanf——一个结构
- 如果我们打算写一个函数来读入结构
- 但是读入的结构如何送回来呢?
- C语言在函数调用时是传值的
- 在函数读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}
- 解决方案
- 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
- 问题在于传入函数的是外面那个结构的克隆体,而不是指针
- 传入结构和传入数组是不同的
- 在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者
#include
structpoint {
intx;
inty;
};
voidgetStruct(structpoint);
voidoutput(structpoint);
intmain(intargc,charconst*argv[])
{
structpointy= {0,0};
getStruct(y);
output(y);
}
voidgetStruct(structpointp)
{
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("%d,%d",p.x,p.y);
}
voidoutput(structpointp)
{
printf("%d,%d",p.x,p.y);
}
结构指针作为参数
- K&R说过(p.131)
指向结构的指针
用->表示指针所指的结构变量中的成员
structdate{
intmonth;
intday;
intyear;
}myday;
structdate*p=&myday;
(*p).month=12;
p->month=12;
//第九行跟第十行是一样的意思,第十行会更便捷
#include
structpoint {
intx;
inty;
};
structpoint*getStruct(structpoint*);
voidoutput(structpoint);
voidprint(conststructpoint*p);
intmain(intargc,charconst*argv[])
{
structpointy= {0,0};
getStruct(&y);
output(y);
output(*getStruct(&y));
print(getStruct(&y));
*getStruct(&y) = (structpoint){1,2};
}
structpoint*getStruct(structpoint*p)
{
scanf("%d",&p->x);
scanf("%d",&p->y);
printf("%d,%d",p->x,p->y);
returnp;
}
voidoutput(structpointp)
{
printf("%d,%d",p.x,p.y);
}
voidprint(conststructpoint*p);
{
printf("%d,%d",p->x,p->y);
}
11.2-3结构中的结构
结构数组
- struct date dates[100]; //这是在初始化数组
- struct date dates[] = {{4,5,2005},{2,4,2005}};
#include
structtime{
inthour;
intminutes;
intseconds;
};
structtimetimeUpdate(structtimenow);
intmain(void){
structtimetestTimes[5] = {
{11,59,59},{12,0,0},{1,29,59},{23,59,59},{19,12,27}
};
inti;
for(i=0; i<5; ++i){
printf("Time is %.2i:%.2i:%.2i",
testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);
testTimes[i] =timeUpdate(testTimes[i]);
printf("...one second later it's %.2i: %.2i: %.2i\n",
testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);
}
return0;
}
structtimetimeUpdate(structtimenow){
++now.seconds;
if(now.seconds==60 ){
now.seconds=0;
++now.minutes;
if(now.minutes==60 ){
now.minutes=0;
++now.hour;
if(now.hour==24 ){
now.hour=0;
}
}
}
}
structdateAndTime{
structdatesdate;
structtimestime;
};
嵌套的结构
structpoint{
intx;
inty;
};
structrectangle{
structpointpt1;
structpointpt2;
};
如果有变量structrectangler;
就可以有:
r.pt1.x、r.ptl.y
r.pt2.x、r.pt2.y
如果有变量定义:
structrectangler,*rp;
rp=&r;
那么下面的四种形式是等价的:(结构中的结构)
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
但是没有rp->pt1->x(因为pt1不是指针)
结构中的结构的数组
#include
structpoint{
intx;
inty;
};
structrectangle{
structpointp1;
structpointp2;
};
voidprintRect(structrectangler)
{
printf("<%d,%d> to <%d,%d>\n",r.p1.x,r.p1.y,r.p2.x,r.p2.y);
}
intmain(intargc,charconst*argv[])
{
inti;
structrectanglerects[] = {{{1,2},{3.4}},{{5,6},{7,8}}};//2 rectangles
for(i=0;i<2;i++)printRect(rects[i]);
}
11.3-1类型定义
自定义数据类型(typedef)
- C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字
- 比如:typedef int Length;
- 使得Length成为int类型的别名
- 这样,Length这个名字就可以替代int出现在变量定义和参数声明的地方了:
- Length a,b,len;
- Length numbers[10];
Typedef
- 声明新的类型的名字
- 新的名字是某种类型的别名
- 改善了程序的可读性
typedeflongint64_t; //重载已有的类型名字 新名字的含义更清晰 具有移植性
typedefstructADate{
intmonth;
intday;
intyear;
}Date; //简化了复杂的名字
//在这里Date等价于struct ADate,Date代表了到达struct ADate之前的所有
int64_ti=10000000000;
Dated= {9,1,2005};
typedefintLength;//Length就等价于int类型
typedef*char[10]Strings; //String是10个字符串的数组的类型
typedefstructnode{
intdata;
structnode*next;
}aNode;
或
typedefstructnodeaNode;//这样用aNode就可以替代struct node
11.3-2联合
联合
- 存储
- 所有的成员共享一个空间
- 同一时间只有一个成员是有效的
- union的大小是其最大的成员
- 初始化
- 对第一个成员做初始化
#include
typedefunion{
inti;
charch[sizeof(int)];
}CHI;
intmain(intargc,charconstargv[])
{
CHIchi;
inti;
chi.i=1234;
for( i=0;i<sizeof(int);i++){
printf("%02hhX",chi.ch[i]);
}
printf("\n");
return0;
}
//输出D20400, 1234的十六进制是0x04D2
//低位在前(相当于倒置),小端的方式