第十一周:结构类型

简介: 你会坚持下来的对吗?希望C语言不会成为你跨进编程世界的拦路虎,而是你的启蒙语言,梦的开始

11.1-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;

}

枚举

  1. 用枚举而不是定义独立的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;

}

  1. 枚举是一种用户定义的数据类型,它用关键字enum 以如下语法来声明:
  1. enum 枚举类型名字{名字0,.....,名字n};
  2. 枚举类型名字可以省略
  1. 枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n。如:
  1. enum colors{red,yellow,green};
  2. 这样就创建了3个常量,red的值是0,yellow的值是1,而green的值是2
  3. 当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量名字

#include

enumcolor{ red,yellow,green};

voidf(enumcolorc);

intmain(void)

{

   enumcolort=red;

   

   scanf("%d",&t);

   f(t);

   

   return0;

}

voidf(enumcolorc)

{

   printf("%d\n",c);

}

  1. 枚举量可以作为值
  2. 枚举类型可以跟上enum作为类型
  3. 但是实际上是以整数来做内部计算和外部输入输出的

#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;

}

  1. 这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便
  2. 上面的套路:在进行枚举的时候最后面在放上一个数(NumCOLORS),这样就能够表示NumCOLORS前面有几个数了(例如里面有3个数,索引值到0-2,在后面加上一个数,索引值刚好等于实际我们想要表达的数量)

枚举量

  1. 声明变量可以指定值
  1. 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

  1. 即使给枚举类型的变量赋不存在的整数值也没有任何warning或error

枚举

  1. 虽然枚举类型可以当作类型使用,但是实际上很(bu)少(hao)用
  2. 如果有意义上排比的名字,用枚举比const int方便
  3. 枚举比宏(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;

}

//声明结构类型跟定义结构变量是两件事情哦

  1. 声明在函数内还是函数外?
  1. 和本地变量一样(就是局部变量),在函数内部声明的结构类型只能在函数内部使用
  2. 所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了

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;

}

结构成员

  1. 结构和数组有点像
  2. 数组用[]运算符和下标访问其成员
  1. a[0] = 10;
  1. 结构用.运算符和其名字访问其成员
  1. today.day
  2. student.firstName
  3. p1.x
  4. p2.y

结构运算

  1. 要访问整个结构,直接用结构变量的名字
  2. 对于整个结构,可以做赋值、取地址,也可以传递给函数参数
  3. p1 = (struct point){5,10}; //相当于p1.x = 5;p1.y = 10;
  4. p1 = p2;  //相当于p1.x = p2.x;p1.y = p2.y;
  5. 数组无法做这两种运算!但结构可以

结构指针

  1. 和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
  2. 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)

  1. 整个结构可以作为参数的值传入函数
  2. 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
  3. 也可以返回一个结构
  4. 跟数组完全不一样

#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;

}

输入结构

  1. 没有直接的方式可以一次scanf——一个结构
  2. 如果我们打算写一个函数来读入结构
  3. 但是读入的结构如何送回来呢?
  4. C语言在函数调用时是传值的
  5. 在函数读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}
  1. 解决方案
  2. 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
  1. 问题在于传入函数的是外面那个结构的克隆体,而不是指针
  2. 传入结构和传入数组是不同的
  1. 在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者

#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);

}

结构指针作为参数

  1. 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结构中的结构

结构数组

  1. struct date dates[100]; //这是在初始化数组
  2. 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)

  1. C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字
  2. 比如:typedef int Length;
  3. 使得Length成为int类型的别名
  4. 这样,Length这个名字就可以替代int出现在变量定义和参数声明的地方了:
  1. Length a,b,len;
  2. Length numbers[10];

Typedef

  1. 声明新的类型的名字
  1. 新的名字是某种类型的别名
  2. 改善了程序的可读性

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联合

联合

  1. 存储
  1. 所有的成员共享一个空间
  2. 同一时间只有一个成员是有效的
  3. union的大小是其最大的成员
  1. 初始化
  1. 对第一个成员做初始化

#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

//低位在前(相当于倒置),小端的方式

目录
相关文章
|
7月前
|
存储 安全 Unix
C#.Net筑基-类型系统②常见类型--日期和时间的故事
在System命名空间中,有几种表示日期时间的不可变结构体(Struct):DateTime、DateTimeOffset、TimeSpan、DateOnly和TimeOnly。DateTime包含当前本地或UTC时间,以及最小和最大值;DateTimeOffset增加了时区偏移信息,适合跨时区操作。UTC是世界标准时间,而格林尼治标准时间(GMT)不稳定,已被更精确的UTC取代。DateTimeOffset和DateTime提供了转换为UTC和本地时间的方法,以及各种解析和格式化函数。
|
Web App开发 监控
【自然框架】之 “工作日志”和“选择日期”
      上周回家办点事,更新的事情就有耽搁了。对不住大家,所以这周要努力了。       我发现要做的事情太多了,做过了哪些事情也都记不清了,所以有必要弄个“工作计划”和“工作日志”出来。为什么要弄个“工作日志”呢?有这么几个好处。
909 0
|
C++ 人工智能
2015级C++第9周程序阅读 类和指针
阅读程序,写出程序的运行结果并理解其运行机制。 (1) #include &lt;iostream&gt; using namespace std; class A { public: A(){cout&lt;&lt;"A";} ~A(){cout&lt;&lt;"~A";} }; class B { A *p; public: B()
919 0
|
自然语言处理 C++ iOS开发
2014秋C++第17周 项目7参考 电子词典结构体版
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。  【项目7-电子词典结构体版】做一个简单的电子词典。在文件dictionary.txt中,保存的是英汉对照的一个词典,词汇量近8000个,英文、中文释义与词性间用’\t’隔开。编程序,由用户输入英文词
1137 0
|
C++
2014秋C++第17周 项目 结构体登场
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。  【项目1-体会函数参数传递】阅读下面的程序,写出期望中的运行结果。上机运行对照,并用单步执行的方法再次体会,完全掌握用指针和引用作为形式参数的用法。 #include &lt;iostream&gt
1262 0
|
C++
2014秋C++ 第15周项目 指针基础
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。  【项目1-打入“内部”寻“内幕”】下面是一段使用了指针的程序。请利用“单步”执行的方式运行程序,深刻理解“指针变量存储的是地址值”、“通过指针变量间接访问”等概念。将在执行过程中留下深刻映像的界
1046 0
|
存储 C++
C++第11周(春)项目1 - 存储班长信息的学生类
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 【项目1 - 存储班长信息的学生类】 class Stu //声明基类 { public: Stu(int n, string nam ); //基类构造函数 void display( );
1125 0
|
C++
C++第6周(春)项目2 对象作为数据成员
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 【项目2 - 对象作为数据成员】  回想Engineer类的数据成员,有眼镜、背包等。某Engineer的眼镜、背包,是Glass、Bag类的对象。类中的数据成员,其类型可以是简单类型,也可以是类。通过这种方式,将某些类组合到另外的类中,当
1073 0
|
C++ iOS开发
C++第4周(春)项目4 数组作数据成员
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 【项目4 - 数组作数据成员】阅读教材P255例8.4,注意到类中的数据成员可以是数组。设计一个工资类(Salary),其中的数据成员如下类的声明。 class Salary { public: void set
1071 0
|
Go C++ iOS开发
C++第2周(春)项目3 文件+结构体实现实用系统
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 【项目3-文件+结构体实现实用系统】score.txt(本文后提供了一部分数据,自行copy建文本文件)中是一些同学的学号、姓名、C++、高数、英语成绩,利用前两个项目中定义的结构体数组,读取文件中的数据,完成下面的应用: (1)从文件中
1245 0