一、枚举
枚举是一种用户定义的数据类型,它用关键字enum以如下的语法来声明:
enum 枚举类型名字 {名字0,名字1,…,名字n};
(1)用枚举进行输入输出:
- 当我们需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值一些名字。
enum color {red,yellow,green};
enum color t = red;
- 枚举类型可以加上enum作为类型。(实际上很少用)
- void f(enum color c); //枚举量可以作为值。
- 实际上,在C语言内部中,enum就是int,所以每个枚举类型的变量是可以像int一样进行输入与输出的。
(2)自动计数的枚举:
在枚举的定义当中,所有的名字的量是依次递增的,比如enum COLOR{RED,YELLOW,GREEN,NumCOLORS};RED是0,YELLOW是1,GREEN是2,所以跟在最后一个名字后面的量的值就是前面名字的计数,NumCOLORS是3。
定义NumCOLORS来计数枚举类型中有多少个名字,那么就
①可以使用NumCOLORS来定义数组
②可以使用NumCOLORS来判断用户输入的数字是不是再有效的范围内
③可以将NumCOLORS放在for循环中进行遍历所有的枚举量。
(3)声明枚举量的时候可以指定值:
enum COLOR{RED=1,YELLOW,GREEN=5,NumCOLORS};
当RED定义为1的时候,YELLOW就是1+1=2,定义时也可以是离散的,GREEN=5,中间的没有3和4。此时的NumCOLORS就是6了,便不可以用来计数了。
(4)枚举只是int
- 如果是用在有意义上排比的名字,用来定义符号量,用枚举比const int方便。
- 枚举比宏(macro)好,因为枚举有类型而宏没有。
二、结构
一个结构就是一个复合的数据类型,里面有各种数据类型的成员,然后用一个变量来表达那么多的数据。
通常在函数外部声明结构类型。
(1)结构基本知识
1定义结构变量
struct point{
int x;
int y;
}p1,p2;
声明了一个结构叫做point,定义了这种结构的两个变量p1和p2。
2结构变量的初始化:
struct date today = {02,9,2018};
//与数组类似。
3结构成员:
结构里有很多个成员,这些成员可以是不同类型,可以使用小圆点.运算符和成员名字来访问其成员,比如:
today.day; 访问today变量的成员
day p1.x; 访问结构变量p1的成员x
- 结构类型是虚的,结构类型.xxx是没有意义的。
- 结构变量才是实体,在.运算符左边的一定是一个结构变量。
4结构指针
结构变量的名字并不是结构变量的地址,必须使用&运算符。(而数组的名字就是数组的首地址)
struct date *p = &today; //指向结构的指针,&不能去掉。
5结构运算
要访问整个结构,直接用结构变量的名字。
对于整个结构,可以做赋值、取地址、也可以传递给函数参数。
struct point{
int x;
int y;
}p,p2;
赋值:
p=(struct point){ 5,10};//相当于强制转换为p.x=5,p.y=10。
p=p2;//相当于p.x=p2.x,p.y=p2.y;
(2)结构与函数
1.结构作为函数参数:
- 整个结构是可以作为参数的值传入函数的。
- 这时是在函数内新建一个结构变量,并复制调用者的结构的值。
- 也可以返回一个结构。
↓如例:写一程序根据输入的日期,输出第二天的日期。
#include<iostream>
using namespace std;
struct date{
int month;
int day;
int year;
}today,tomorrow;
bool isleapyear(struct date n);
int numberofdays(struct date n);
int main()
{
cout<<"请给定一个日期(mm dd yyyy):";
cin>>today.month>>today.day>>today.year;
if(today.day!=numberofdays(today))
{
tomorrow.day=today.day+1;
tomorrow.month=today.month;
tomorrow.year=today.year;
}
else if(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;
}
cout<<"第二天是"<<tomorrow.month<<'-'<<tomorrow.day<<'-'<<tomorrow.year<<endl;
return 0;
}
bool isleapyear(struct date n)
{
bool leap=false;
if((n.year%4==0&&n.year%100!=0)||n.year%400==0)
leap=true;
return leap;
}
int numberofdays(struct date n)
{
int days;
const int dayspermonth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
if(n.month==2&&isleapyear(n))
days=29;
else
days=dayspermonth[n.month];
return days;
}
运行代码:
2.输入结构:
没有一个直接的方式可以一次scanf一个结构,如果打算写一个函数来读入结构呢?
在getStruct函数中输入4和5之后,该函数内部输出4和5,但是回到main中,y的值依然是0和0.
因为C语言里在函数调用时是传值的。p和y并没有联系。这一点和数组不一样。所以上述代码是不能完成输入结构的。
解决方法一:将结构变量作为函数返回值
解决方法二:结构指针作为函数参数(更好):
在将一个结构传递给函数时,一般不传结构,而是传递结构的指针。
指向结构的指针:
struct date{
int month;
int day;
int year;
} myday;
struct date *p = &myday;//做出一个结构指针指向结构变量myay
(*p).month =12; //①两种写法
p->month =12; //②一般说成p所指的(那个结构的)month
用->表示指针所指的结构变量中的成员。
(3)结构中的数组
1.结构数组
输出一系列时间的后一分钟:
#include <stdio.h>
struct time
{
int hour;
int minutes;
int seconds;
};
struct time timeUpdate(struct time now); //函数参数是struct time类型变量,返回值也是struct time类型
int main(void)
{
struct time testTimes[5]={
{11,59,59},{12,0,0},{1,29,59},{23,59,59},{19,12,27}
};//结构中的数组
int i;
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]);//testTimes[i]这个结构变量作为参数传递给函数,并接收返回值
printf("...one second later it's %.2i:%.2i:%.2i\n",testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);
}
return 0;
}
struct time timeUpdate(struct time now)
{ //时间+1分钟
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;
}
}
}
return now;
}
程序运行:
2结构中的结构:zzz
3结构中结构的数组:zzz
三、类型定义与联合
1.类型定义(typedef)
typedef的作用是声明一个数据类型的新名字,新名字相当于该数据类型的别名,改善了程序的可读性。
2.联合(union)
struct中的两个成员是分开的,是可以随意使用的。但是对于union来说,这两个成员占据了同一个空间。
联合在存储的时候,所有成员共享一个空间,同一时间只有一个成员是有效的。
union的空间是其最大成员的大小。对联合进行初始化的时候,只需对第一个成员做初始化。